Preliminaries


library (tidyverse)
library (dplyr)
library (sf)
library (rnaturalearth)
library (viridis)
library (gganimate)
library (gifski)
library (ggridges)

Data preparation

Source: World Development Indicators: https://databank.worldbank.org/source/world-development-indicators Series related to economy, education, environment, health, labor, poverty and public sector

# Reading files  
# wdi <- world development indicators 
# ind <- indicators selected
# df_cont <- main indicators calculated by continent
# world <- world basic indicators

wdi <- read.csv ("./data/wdi.csv", header = TRUE, sep = ",", na="..")
ind <- read.csv ("./data/indicators_selected.csv", header = TRUE, sep = ";", na="")
df_cont <- read.csv ("./data/indicators_by_continent.csv", header = TRUE, sep = ",", na="..", col.names = c("year", "year_code", "continent", "continent_code", "unemp", "emp_vuln", "out_sch_ado", "out_sch_child", "pov_ratio"))
# Extracting the selected indicators into the data from the world bank database, joining the 2 tables
# Transforming the columns with the years in rows (under the column year)
# Changing the format of the column year from X1971..YR1971. to 1971


df <- inner_join (wdi, ind, by = c("ï..Series.Name" = "series_name"))
df <- pivot_longer (df, 'X1971..YR1971.': 'X2020..YR2020.', names_to='year', values_to='values') 
df <- mutate (df, year = as.integer(str_sub(year, start = 2, end = 5)))
# Renaming some columns and keeping only the data which interest us
# Transforming each indicator in columns  (under the column year)

#colnames (df)
df<- rename(df, country_name = Country.Name, country_code = Country.Code)
df<- select (df, indicator, country_name, country_code, year, values)
df <- pivot_wider (df, names_from = "indicator", values_from = "values")
# Including some columns to analyze inequality
# Including a column with the percentage difference between the income share held by highest 10% and income share held by lowest 10%
# Including a column with the percentage difference between the income share held by highest 20% and income share held by lowest 20%

df<- df %>%
mutate (ineq_10 = inc_high10/inc_low10 -1)%>%
mutate (ineq_20 = inc_high20/inc_low20 -1)
# Writing data in a table
write.table(df, file= "df.csv")

Georeferencing the data

df <- read.table("df.csv")
# Obtaining the georeferenced database for the countries 

countries <- ne_countries(scale = "large", returnclass = "sf")
colnames (countries)
 [1] "featurecla" "scalerank"  "labelrank"  "sovereignt" "sov_a3"     "adm0_dif"   "level"      "type"       "admin"      "adm0_a3"   
[11] "geou_dif"   "geounit"    "gu_a3"      "su_dif"     "subunit"    "su_a3"      "brk_diff"   "name"       "name_long"  "brk_a3"    
[21] "brk_name"   "brk_group"  "abbrev"     "postal"     "formal_en"  "formal_fr"  "name_ciawf" "note_adm0"  "note_brk"   "name_sort" 
[31] "name_alt"   "mapcolor7"  "mapcolor8"  "mapcolor9"  "mapcolor13" "pop_est"    "pop_rank"   "gdp_md_est" "pop_year"   "lastcensus"
[41] "gdp_year"   "economy"    "income_grp" "wikipedia"  "fips_10_"   "iso_a2"     "iso_a3"     "iso_a3_eh"  "iso_n3"     "un_a3"     
[51] "wb_a2"      "wb_a3"      "woe_id"     "woe_id_eh"  "woe_note"   "adm0_a3_is" "adm0_a3_us" "adm0_a3_un" "adm0_a3_wb" "continent" 
[61] "region_un"  "subregion"  "region_wb"  "name_len"   "long_len"   "abbrev_len" "tiny"       "homepart"   "min_zoom"   "min_label" 
[71] "max_label"  "ne_id"      "wikidataid" "name_ar"    "name_bn"    "name_de"    "name_en"    "name_es"    "name_fr"    "name_el"   
[81] "name_hi"    "name_hu"    "name_id"    "name_it"    "name_ja"    "name_ko"    "name_nl"    "name_pl"    "name_pt"    "name_ru"   
[91] "name_sv"    "name_tr"    "name_vi"    "name_zh"    "geometry"  
# Selecting only the columns of interest

countries <- countries%>%
select (name, continent, adm0_a3, iso_a3, economy, income_grp, geometry)

# Other columns: type, admin, region_un, subregion, region_wb, pop_est, pop_rank, gdp_md_est, pop_year, lastcensus,  gdp_year 
# Analyzing which columns will not match in joining and treating them

no_meet <-anti_join(df, countries, by = c( "country_code"= "iso_a3")) 
no_meet%>%
  distinct(country_code)

countries<- countries%>%
mutate(cod = case_when(
         adm0_a3=='FRA'~ 'FRA',
         adm0_a3=='KOS'~ 'XKX',
         adm0_a3=='NOR'~ 'NOR',
         adm0_a3=='GGY'~ 'CHI',
         TRUE ~ iso_a3
         )
)
countries
Simple feature collection with 255 features and 7 fields
geometry type:  MULTIPOLYGON
dimension:      XY
bbox:           xmin: -180 ymin: -90 xmax: 180 ymax: 83.6341
CRS:            +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
First 10 features:
        name     continent adm0_a3 iso_a3                    economy              income_grp                       geometry  cod
1  Indonesia          Asia     IDN    IDN   4. Emerging region: MIKT  4. Lower middle income MULTIPOLYGON (((117.7036 4....  IDN
2   Malaysia          Asia     MYS    MYS       6. Developing region  3. Upper middle income MULTIPOLYGON (((117.7036 4....  MYS
3      Chile South America     CHL    CHL    5. Emerging region: G20  3. Upper middle income MULTIPOLYGON (((-69.51009 -...  CHL
4    Bolivia South America     BOL    BOL    5. Emerging region: G20  4. Lower middle income MULTIPOLYGON (((-69.51009 -...  BOL
5       Peru South America     PER    PER    5. Emerging region: G20  3. Upper middle income MULTIPOLYGON (((-69.51009 -...  PER
6  Argentina South America     ARG    ARG    5. Emerging region: G20  3. Upper middle income MULTIPOLYGON (((-67.28475 -...  ARG
7   Dhekelia          Asia     ESB   <NA> 2. Developed region: nonG7 2. High income: nonOECD MULTIPOLYGON (((33.78094 34... <NA>
8     Cyprus          Asia     CYP    CYP       6. Developing region 2. High income: nonOECD MULTIPOLYGON (((33.78183 34...  CYP
9      India          Asia     IND    IND   3. Emerging region: BRIC  4. Lower middle income MULTIPOLYGON (((77.80035 35...  IND
10     China          Asia     CHN    CHN   3. Emerging region: BRIC  3. Upper middle income MULTIPOLYGON (((78.91595 33...  CHN
# joining the main data frame with the table containing the geographic information of the countries
# verifying the number of lines and if all rows matched appropriately, using
# anti_join() - return all rows from x where there are not matching values in y, keeping just columns from x

df_geo <- left_join (df, countries, by = c( "country_code"= "cod"))
# Writing data in a table
# write.table(df_geo, file= "df_geo.csv")

Preparing some dataset, according to the theme


# Extracting the main indicators and fill the blank values with the more recent 

df_fill <- df_geo %>%
select (country_name, country_code, continent, year, pop, pov_ratio, out_sch_child, unemp, emp_vuln, ineq_10, ineq_20, inc_low10, inc_low20, inc_low20_40, inc_low40_60, inc_low60_80, inc_high10, inc_high20, pop_slum, lend_bor, acc_wat, acc_ele, acc_san, child_mort, geometry)%>%
# filter (year== 2017) as 
# count(is.na(pov_ratio)) #Verify the quantity of NA data
# As there are many countries without data, I will fill with data from 2010 to 2020 (including the latest data)
filter (year>= 2010) %>%
group_by(country_name) %>%
fill(pop:child_mort) %>%
ungroup ()  %>%
filter (year== 2020)


# creating specific tables for each analyse

poverty<- df_fill%>%
  drop_na ("pov_ratio")

education<- df_fill%>%
  drop_na ("out_sch_child")

inequality<- df_fill%>%
  drop_na ("ineq_10")

unemployment<- df_fill%>%
  drop_na ("unemp")

emp_vulnerable<- df_fill%>%
  drop_na ("emp_vuln")

income10 <- df_fill %>% # selecting data related to income and inequality
  select (country_name, continent, year, ineq_10, inc_low10, inc_high10) %>%
  drop_na (inc_low10, inc_high10) %>%
  pivot_longer ("inc_low10": "inc_high10", names_to = "indicator", values_to = "values")

income20 <- df_fill %>% # selecting data related to income and inequality - quintiles
  select (country_name, continent, year, ineq_20, inc_low20, inc_low20_40, inc_low40_60, inc_low60_80, inc_high20) %>%
  drop_na (inc_low20, inc_low20_40, inc_low40_60, inc_low60_80, inc_high20) %>%
  pivot_longer ("inc_low20": "inc_high20", names_to = "indicator", values_to = "values")


df_fill_hist <- df_geo %>% # selecting historic data and fill the null values (for use in the animated graphic)
select (country_name, continent, year, pop, pov_ratio, out_sch_child, unemp, emp_vuln, acc_wat, acc_ele, acc_san, child_mort)%>%
filter (year>= 1980) %>%
group_by(country_name) %>%
fill(pop:child_mort) %>%
ungroup ()%>%
filter (year>= 1990)
#filter (year== 1990 | year== 2000 | year== 2020)

df_hist <- df_geo %>% # selecting historic data without any fill
select (country_name, continent, year, pov_ratio, out_sch_child, unemp, emp_vuln, pop)
#drop_na (pov_ratio)

Generating models of graphics for analyses

Maps (1)

# This function generates a colored map, according to the ranking of countries in a specific indicator
map_indicator <- function(df_fields, df, indicator, ind, orientation){
  
  # Text for title
  subject<- subset (df_fields, indicator==ind, select= "dataset")
  series <- subset (df_fields, indicator==ind, select= "series")
  unit <- subset (df_fields, indicator==ind, select= "unit")
  title = paste (series, unit)

  # Text for label
  
  if (orientation ==1){ 
    df1<- df%>%
    drop_na (!!indicator)%>%
    group_by (group =  factor(ntile(!!indicator, 5))) %>%
    summarise (upper = max(!!indicator), lower = min(!!indicator)) %>%
    mutate(label = str_c(sprintf("%.1f", lower), " to ", sprintf("%.1f", upper)))
      }
  else{
    df1<- df%>%
    drop_na (!!indicator)%>%
    group_by (group =  factor(ntile(desc(!!indicator), 5))) %>%
    summarise (upper = max(!!indicator), lower = min(!!indicator)) %>%
    mutate (label = str_c(sprintf("%.1f", lower), " to ", sprintf("%.1f", upper)))
      }
  
    # print (head(df1))
    
  if (orientation == 1)
{
  data <- st_sf(df)  
  ggplot() +
    geom_sf(data= data, aes(fill = factor(ntile((!!indicator),5)))) +
    scale_fill_viridis_d(name = paste (subject, "(5 ntile)"), labels = c (df1$label))+
    labs (title = title, caption = "Latest data, between the years 2010 to 2020")+
    # geom_sf_text(data=data, aes(label = str_wrap(indicator, 1)), size = 4)+
    theme_void()
}
else
{
  data <- st_sf(df)
  ggplot() +
    geom_sf(data= data, aes(fill = factor(ntile(desc(!!indicator),5)))) +
    scale_fill_viridis_d(name = paste (subject, "(5 ntile)"), labels = c (df1$label))+
    labs (title = title, caption = "Latest data, between the years 2010 to 2020")+
    # geom_sf_text(data=data, aes(label = str_wrap(indicator, 1)), size = 4)+
    theme_void()
}
}

# Inputs for the analyses
map_indicator (ind, df_fill, quo(pov_ratio), "pov_ratio", -1)
`summarise()` ungrouping output (override with `.groups` argument)

Maps (2)

# This function generates a colored map of one continent, according to the ranking of countries in a specific indicator
map_indicator_continent <- function(cont, df_fields, df, indicator, ind, orientation){
  
  # Text for title
  subject<- subset (df_fields, indicator==ind, select= "dataset")
  series <- subset (df_fields, indicator==ind, select= "series")
  unit <- subset (df_fields, indicator==ind, select= "unit")
  title = paste (series, unit)

  # Text for label
  
  if (orientation ==1){ 
    df1<- df%>%
    filter (continent==cont)%>%
    drop_na (!!indicator)%>%   
    group_by (group =  factor(ntile(!!indicator, 5))) %>%
    summarise (upper = max(!!indicator), lower = min(!!indicator)) %>%
    mutate(label = str_c(sprintf("%.1f", lower), " to ", sprintf("%.1f", upper)))
      }
  else{
    df1<- df%>%
    filter (continent==cont)%>%
    drop_na (!!indicator)%>%
    group_by (group =  factor(ntile(desc(!!indicator), 5))) %>%
    summarise (upper = max(!!indicator), lower = min(!!indicator)) %>%
    mutate (label = str_c(sprintf("%.1f", lower), " to ", sprintf("%.1f", upper)))
      }
  
    #print (head(df1))
    
   
  if (orientation == 1)
{
    data <- st_sf(df)%>%
    filter (continent==cont)
  ggplot() +
    geom_sf(data= data, aes(fill = factor(ntile((!!indicator),5)))) +
    scale_fill_brewer (name = paste (subject, "(5 ntile)"), labels = c (df1$label), direction=-1)+
    # geom_sf_text(data= data, aes(label = country_code), size = 4)+
    # geom_sf_text(data=data, aes(label = str_wrap(!!indicator, 1)), size = 3, fontface = "bold")+
    labs (title = title, caption = "Latest data, between the years 2010 to 2020")+
    theme_void()
}
else
{
    data <- st_sf(df)%>%
    filter (continent==cont)
    ggplot() +
    geom_sf(data= data, aes(fill = factor(ntile(desc(!!indicator),5)))) +
    scale_fill_brewer (name = paste (subject, "(5 ntile)"), labels = c (df1$label), direction=-1)+
    # geom_sf_text(data= data, aes(label = country_code), size = 4)+
    # geom_sf_text(data=data, aes(label = str_wrap(!!indicator, 1)), size = 3, fontface = "bold")+
    labs (title = title, caption = "Latest data, between the years 2010 to 2020")+
    theme_void()
}
}

map_indicator_continent ("Africa", ind, df_fill, quo(pov_ratio), "pov_ratio", -1)
`summarise()` ungrouping output (override with `.groups` argument)

Maps (3)

# This function generates a map with diverging colors, according to the valuer of a specific indicator
map_indicator_diverging <- function(df_fields, df, indicator, ind, orientation){
  
 library("colorspace")
  
  # Text for title
  subject<- subset (df_fields, indicator==ind, select= "dataset")
  series <- subset (df_fields, indicator==ind, select= "series")
  unit <- subset (df_fields, indicator==ind, select= "unit")
  title = paste (series, unit)

  if (orientation == 1)
{
  data <- st_sf(df)  
  ggplot() +
    geom_sf(data= data, aes(fill = !!indicator)) +
     scale_fill_gradientn (colors = c("darkred", "red", "white", "blue", "darkblue"), breaks = c (-30,-10,0,10,30), na.value = "grey50")+
    labs (title = title, caption = "Latest data, between the years 2010 to 2020")+
    # geom_sf_text(data=data, aes(label = str_wrap(indicator, 1)), size = 4)+
    theme_void()
}
else
{
  data <- st_sf(df)
  ggplot() +
    geom_sf(data= data, aes(fill = !!indicator)) +
    scale_fill_gradientn (colors = c ("darkred", "red", "white", "blue", "darkblue"), breaks = c (-30,-10,0,10,30), na.value = "grey50")+
    labs (title = title, caption = "Latest data, between the years 2010 to 2020")+
    # geom_sf_text(data=data, aes(label = str_wrap(indicator, 1)), size = 4)+
    theme_void()
}
}

# Inputs for the analyses
map_indicator_diverging (ind, df_fill, quo(lend_bor), "lend_bor", -1)

Histograms

# This function generate a histogram for a specific indicator
histogram <- function(df_fields, df, indicator, ind){

# Extracting the details of the fields from the data frame (name of the subject, indicator (series) and unit)
subject<- subset (df_fields, indicator==ind, select= "dataset") # or ind%>% filter (indicator=="pov_ratio")%>% select ("dataset")
series <- subset (df_fields, indicator==ind, select= "series")
unit <- subset (df_fields, indicator==ind, select= "unit")
countries <- length(indicator)

lab_title <- paste ("# of countries according to the level of", subject)
lab_x = paste (series, unit)

      
df %>%

ggplot (aes (indicator))+
  geom_histogram(breaks=seq (0,100, by = 10), color = "darkblue", fill = "steelblue")+
  scale_x_continuous(breaks = seq (0, 100, by = 10))+
  stat_bin(binwidth = 10, geom='text', color = "white", center = 5, aes(label=(..count..)), position=position_stack(0.5))+
  labs (title = lab_title, x=lab_x, y = "# of countries", caption = "Latest data between the years 2010 to 2020")+
  geom_text (x = 80, y = 30, label = paste("# of countries analyzed=", countries))

}

histogram (ind, poverty, poverty$pov_ratio, "pov_ratio")+
geom_text(x = 40, y = 50, label = "10 countries with more than 50% of the population
          living in conditions of extreme poverty", hjust = 0, vjust = 0.5, colour = "red", size = 4)+
geom_segment(aes(x = 55, y = 40, xend = 55, yend = 15), colour="red", size=0.5, arrow = arrow(length = unit(0.5, "cm")))+

geom_text(x = 20, y = 70, label = "35 countries with more than 20% of the population
          living in conditions of extreme poverty", hjust = 0, vjust = 0.5, colour = "red", size = 4)+
geom_segment(aes(x = 25, y = 60, xend = 25, yend = 15), colour="red", size=0.5, arrow = arrow(length = unit(0.5, "cm")))

Columns - Top countries


# This function generate a list with the ranking countries in one specific indicator (maximum)
top_countries_max <- function(df_fields, df, indicator, ind){
  
n=35

# Text for labs (x, y and title)
subject<- subset (df_fields, indicator==ind, select= "dataset")
series <- subset (df_fields, indicator==ind, select= "series")
unit <- subset (df_fields, indicator==ind, select= "unit")

lab_title <- paste ("Top", n,  "countries with worst levels of", subject)
lab_x = paste (series, unit)
  
# Plot 
df %>%
slice_max(!!indicator, n = n)%>%
ggplot (aes (x= !!indicator, y= reorder(country_name, !!indicator, max), fill=continent))+ 
  geom_text(aes(label=round(!!indicator,2), hjust=-0.3),size=5)+
  scale_fill_manual (values = c("indianred1", "yellow", "deeppink1","cyan", "orange", "gray", "seagreen3"), breaks = c("Africa", "Asia", "Europe","North America", "Oceania", "Seven Seas", "South America"))+
  geom_bar(stat="identity")+
  labs (title = lab_title, x=lab_x, y = "Countries", caption = "Latest data between the years 2010 to 2020")+
  theme(text = element_text(size = 20), legend.position = "bottom")
  
  }

top_countries_max (ind, poverty, quo(pov_ratio), "pov_ratio")

Columns - Top countries


# This function generate a list with the ranking countries in one specific indicator (minimum)
top_countries_min <- function(df_fields, df, indicator, ind){
  
n=35

# Text for labs (x, y and title)
subject<- subset (df_fields, indicator==ind, select= "dataset")
series <- subset (df_fields, indicator==ind, select= "series")
unit <- subset (df_fields, indicator==ind, select= "unit")

lab_title <- paste ("Top", n,  "countries with worst levels of", subject)
lab_x = paste (series, unit)
  
# Plot 
df %>%
slice_min(!!indicator, n = n)%>%
ggplot (aes (x= !!indicator, y= reorder(country_name, !!indicator, min), fill=continent))+ 
  geom_text(aes(label=round(!!indicator,2), hjust=-0.3),size=5)+
  scale_fill_manual (values = c("indianred1", "yellow", "deeppink1","cyan", "orange", "gray", "seagreen3"), breaks = c("Africa", "Asia", "Europe","North America", "Oceania", "Seven Seas", "South America"))+
  geom_bar(stat="identity")+
  labs (title = lab_title, x=lab_x, y = "Countries", caption = "Latest data between the years 2010 to 2020")+
  theme(text = element_text(size = 20), legend.position = "bottom")
  
  }

top_countries_min (ind, poverty, quo(lend_bor), "lend_bor")

Boxplot

# This function generates a boxplot of the indicator for each continent 
box_plot <- function(df_fields, df, indicator, ind){
  
# Text for labs (x, y and title)
subject<- subset (df_fields, indicator==ind, select= "dataset")
series <- subset (df_fields, indicator==ind, select= "series")
unit <- subset (df_fields, indicator==ind, select= "unit")

lab_title <- paste ("Boxplot - ", series, "by continent", unit)
lab_y = paste (series, unit)

df %>%
drop_na (!!indicator)%>%
ggplot (aes(x=continent, y= !!indicator, fill = continent, label = country_name),size = pop)+
  geom_boxplot (alpha = 0.6)+
  #geom_violin()+
  geom_point(alpha = 0.6)+
  labs (title = lab_title, y=lab_y)+
  #geom_text(hjust = -.1, nudge_x=0.02, alpha = .4)+
  theme(text = element_text(size = 20))

}

box_plot (ind, df_fill, quo(pov_ratio), "pov_ratio")

Historic per country and year


# This function generates a graph with the history of each variable for each country 
plot_hist_countries <- function (df_fields, df, indicator, ind, orientation){

# Text for labs (x, y and title)
series <- subset (df_fields, indicator==ind, select= "series")
unit <- subset (df_fields, indicator==ind, select= "unit")

lab_title <- paste (series, "per country along the years", unit)


df%>%
ggplot (aes (x= year, y= reorder(country_name, !!indicator, max), color= !!indicator, size=!!indicator))+
  scale_color_viridis_c (direction= orientation)+
  geom_point()+
  scale_x_continuous (breaks = seq(1970, 2020, by = 10))+
  theme(text = element_text(size = 25))+
  labs (title = lab_title, x="Years", y = "countries")+
  facet_wrap ('continent', scales = 'free')

}
plot_hist_countries (ind, poverty_hist, quo(pov_ratio), "pov_ratio", -1)

Hot maps

# This function generates a hot map of the indicator by continent 

hot_map <- function (df_fields, df, indicator, ind, orientation){
  
# Text for labs (title)
subject<- subset (df_fields, indicator==ind, select= "dataset")
series <- subset (df_fields, indicator==ind, select= "series")
unit <- subset (df_fields, indicator==ind, select= "unit")
lab_title <- paste ("Hot map - ", series, unit)

# Limits for the legend
if (orientation ==-1){ 
    df1<- df%>%
    drop_na (!!indicator)%>%
    group_by (group =  factor(ntile(!!indicator, 5))) %>%
    summarise (upper = max(!!indicator), lower = min(!!indicator)) %>%
    mutate(label = str_c(sprintf("%.1f", lower), " to ", sprintf("%.1f", upper)))
      }
  else{
    df1<- df%>%
    drop_na (!!indicator)%>%
    group_by (group =  factor(ntile(desc(!!indicator), 5))) %>%
    summarise (upper = max(!!indicator), lower = min(!!indicator)) %>%
    mutate (label = str_c(sprintf("%.1f", lower), " to ", sprintf("%.1f", upper)))
  }
# print(df1)

df%>%
drop_na (!!indicator) %>%

ggplot (aes (x= year, y= continent, fill = (ntile(!!indicator, 5))))+ 
  geom_tile()+
  scale_fill_viridis (name = paste (subject, "(5 ntile)"), direction = orientation, labels = c (df1$label))+
  scale_x_discrete (breaks = seq (1950, 2020, by=5))+
  labs (title = lab_title, y = "Continent", x= "Year", caption = "Latest data between the years 2010 to 2020")
  #theme(text = element_text(size = 15))
}

hot_map (ind, df_cont, quo(emp_vuln), "emp_vuln", -1)
`summarise()` ungrouping output (override with `.groups` argument)

Correlation

# This function generates a graph with the correlation between 2 variables 
correlation <- function (df_fields, df, indicator1, indicator2, ind1, ind2){
  
  
# Text for title
series1 <- subset (df_fields, indicator==ind1, select= "series")
unit1 <- subset (df_fields, indicator==ind1, select= "unit")
series2 <- subset (df_fields, indicator==ind2, select= "series")
unit2 <- subset (df_fields, indicator==ind2, select= "unit")

lab_x <- paste (series1, unit1)
lab_y <- paste (series2, unit2)
lab_title <- paste (lab_x, "x", lab_y)
  
df%>%
  drop_na (!!indicator1, !!indicator2)%>%

ggplot (aes (x= !!indicator1, y= !!indicator2, color = continent,label = country_name, size = ntile(pop,5)))+
  geom_point(alpha = 0.6)+
  scale_colour_manual (values = c("indianred1", "yellow", "deeppink1","cyan", "orange", "gray", "seagreen3"))+
  labs (title = lab_title, x=lab_x, y = lab_y, caption = "Latest data between the years 2010 to 2020")+
  geom_text(hjust = -.1, nudge_x=0.02, alpha = .3)

}

correlation (ind, df_fill, quo(ineq_10), quo(pov_ratio), "ineq_10", "pov_ratio")

Other graphics, more specific and complex, were included at the end of the report.

REPORT

** OVERVIEW OF POVERTY, EDUCATION AND EMPLOYMENT IN THE WORLD**

POVERTY

Where do the world’s poorest people live today?

map_indicator (ind, df_fill, quo(pov_ratio), "pov_ratio", -1)

Approximately 1/5 of the countries in the world have more than 26% of the population living with up to 1.90 a day. These countries are concentrated in Africa.

map_indicator_continent ("Africa", ind, df_fill, quo(pov_ratio), "pov_ratio", -1)

Analyzing Africa in more detail, it is possible to see the largest region of poverty, where 51 to 77% of population is living with up to 1.90 a day.

Under what conditions people live today?

map_indicator (ind, df_fill, quo (pop_slum),"pop_slum", -1)

map_indicator (ind, df_fill, quo (acc_ele),"acc_ele", 1)

map_indicator_continent ("Africa", ind, df_fill, quo(acc_ele), "acc_ele", 1) # Zoom in Africa, but there are other continents with low values

map_indicator (ind, df_fill, quo (acc_wat),"acc_wat", 1)

map_indicator (ind, df_fill, quo (acc_san),"acc_san", -1)

map_indicator_continent ("Africa", ind, df_fill, quo(acc_san), "acc_san", -1) # Zoom in Africa, but there are other continents with low values

map_indicator (ind, df_fill, quo (child_mort),"child_mort", -1)

There are still many countries with a high percentage of the population living in subhuman conditions:

  • Approximately 3/5 of the countries have more than 27% of urban population living in slums; 1/5 of the countries have from 58% up to 95% of urban population living in slums;
  • There are countries with only 11% to 30% of the population with access to electricity;
  • 1/5 of the countries in the world have a low percentage of the population with access to basic drinking water services (38% to 78% of the population);
  • And countries with 40% to 68% of the population practicing open defecation;
  • In Africa and some countries of Asia there is a high infant mortality rate (36 to 81 per 1,000 live births).

Where do the world’s poorest people live today?

histogram (ind, poverty, poverty$pov_ratio, "pov_ratio")+
geom_text(x = 40, y = 50, label = "10 countries with more than 50% of the population
          living in conditions of extreme poverty", hjust = 0, vjust = 0.5, colour = "red", size = 4)+
geom_segment(aes(x = 55, y = 40, xend = 55, yend = 15), colour="red", size=0.5, arrow = arrow(length = unit(0.5, "cm")))+

geom_text(x = 20, y = 70, label = "35 countries with more than 20% of the population
          living in conditions of extreme poverty", hjust = 0, vjust = 0.5, colour = "red", size = 4)+
geom_segment(aes(x = 25, y = 60, xend = 25, yend = 15), colour="red", size=0.5, arrow = arrow(length = unit(0.5, "cm")))

top_countries_max (ind, poverty, quo(pov_ratio),"pov_ratio")

The top 30 countries with extremely poverty are from Africa.

How is the behaviour of extreme poverty by continent?

box_plot (ind, df_fill, quo(pov_ratio), "pov_ratio")

# box_plot (ind, df_fill, quo(acc_ele), "acc_ele")

In addition to Africa, Asia, North America and Oceania have countries with more than 20% of the population living in poverty.

How has evolved poverty per country along the years?

plot_hist_countries (ind, df_hist, quo(pov_ratio), "pov_ratio", -1)

The extremely poverty is decreasing in the majority of countries in the world.

Asia: considerable reduction in extreme poverty, e.g.,Indonesia, China, Nepal and India. Only one exception: Uzbekistan, but there is no data from recent years of this country. Americas: also had a reduction, with exception of Venezuela (that doesn’t have data for the recent years). Oceania and Europe: values have decreased or remain relatively low over the years. In Africa, there are more extreme poverty and although it is decreasing in many countries, in some others it is increasing (Madagascar, Malawi, Guinea Bissau, Angola, Sao Tome and Principe, Zambia, Zimbabwe and Cote d’Ivoire).

How has evolved the poverty by continent along the years?

hot_map (ind, df_cont, quo(pov_ratio), "pov_ratio", -1)
`summarise()` ungrouping output (override with `.groups` argument)

The graph above shows the improvement in performance on this indicator in all continents. Only in Middle East & North Africa this indicator worsened in recent years.

EDUCATION

"In which countries are more children out of school?

map_indicator (ind, df_fill, quo(out_sch_child),"out_sch_child", -1)

Approximately 1/5 of the countries have more than 12% of the children out of school.

histogram (ind, education, education$out_sch_child, "out_sch_child")+
geom_text(x = 40, y = 50, label = "2 countries with more than 50% of the children 
          out of school (% of primary school age)", hjust = 0, vjust = 0.5, colour = "red", size = 4)+
geom_segment(aes(x = 55, y = 40, xend = 55, yend = 15), colour="red", size=0.5, arrow = arrow(length = unit(0.5, "cm")))+

geom_text(x = 20, y = 70, label = "21 countries with more than 20% of the children out of school 
          (% of primary school age)", hjust = 0, vjust = 0.5, colour = "red", size = 4)+
geom_segment(aes(x = 25, y = 60, xend = 25, yend = 15), colour="red", size=0.5, arrow = arrow(length = unit(0.5, "cm")))

top_countries_max (ind, education, quo(out_sch_child),"out_sch_child")

South Sudan is the worst country in this indicator, with 62.3% of children out of school (% of primary school age). In North America, Turks and Caicos Islands is the worst country in primary education, with 27.84% of children out of school. Syrian Arab Republic in Asia, with 27.61% of children out of school. Marshall Islands in Oceania, with 25.86% of children out of school. Bulgaria appears in the 35th position in the ranking of countries with the most children out of school.

How are the education indicator statistics by continent (boxplot)?

box_plot (ind, df_fill, quo(out_sch_child),"out_sch_child")

How has evolved the education indicator per country along the years?

plot_hist_countries (ind, df_hist, quo(out_sch_child), "out_sch_child", -1)

The vast majority of countries in the world are improving their performance in this indicator. However, there are still some countries that are getting worse, such as South Sudan, Equatorial Guinea, Congo (Dem. Rep.), Turcs and Caicos Islands, Suriname, Bolivia. Paraguay and Venezuela already improved and got worse.

How has evolved the education indicator by continent along the years?

hot_map (ind, df_cont, quo(out_sch_child), "out_sch_child", -1)
`summarise()` ungrouping output (override with `.groups` argument)

The graph above shows the improvement in performance on this indicator in all continents.

EMPLOYMENT

In which countries are more unemployment and vulnerable employment?

map_indicator (ind, df_fill, quo(unemp),"unemp", -1)

map_indicator (ind, df_fill, quo (emp_vuln),"emp_vuln", -1)

Approximately 1/5 of the countries have more than 11% of unemployment (persons unemployed/ total labor force). Approximately 2/5 of the countries have more than 40% of vulnerable employment (% of total employment).

histogram (ind, unemployment, unemployment$unemp, "unemp")+
geom_text(x = 20, y = 70, label = "7 countries with more than 20% of the labour force unemployed)", hjust = 0, vjust = 0.5, 
          colour = "red", size = 4)+
geom_segment(aes(x = 25, y = 60, xend = 25, yend = 15), colour="red", size=0.5, arrow = arrow(length = unit(0.5, "cm")))

histogram (ind, emp_vulnerable, emp_vulnerable$emp_vuln, "emp_vuln")+
geom_text(x = 40, y = 40, label = "59 countries with more than 50% of 
          vulnerable employment)", hjust = 0, vjust = 0.5, colour = "red", size = 4)+
geom_segment(aes(x = 55, y = 35, xend = 55, yend = 15), colour="red", size=0.5, arrow = arrow(length = unit(0.5, "cm")))+

geom_text(x = 27, y = 50, label = "116 countries with more than 20% of 
          vulnerable employment)", hjust = 0, vjust = 0.5, colour = "red", size = 4)+
geom_segment(aes(x = 25, y = 53, xend = 25, yend = 25), colour="red", size=0.5, arrow = arrow(length = unit(0.5, "cm")))

top_countries_max (ind, unemployment, quo(unemp),"unemp")

top_countries_max (ind, emp_vulnerable, quo (emp_vuln),"emp_vuln")

Unemployment:

There are countries from all continents in this ranking. South Africa appears first in the ranking with 28% unemployment.

Vulnerable employment:

These 35 countries have more than 71% of people working in vulnerable employment. Burundi, Niger, Chad, Central African and Guinea are countries with more percentage of vulnerable employment in Africa. In Asia, Korea, Afghanistan, Lao PDR, Congo and India have the worst performance in this indicator. Also, Papua New Guinea in Oceania and Haiti in North America are in the ranking.

How are the unemployment and vulnerable employment indicators statistics by continent (boxplot)?

box_plot (ind, df_fill, quo(unemp),"unemp")

box_plot (ind, df_fill, quo (emp_vuln),"emp_vuln")

How have evolved unemployment and vulnerable employment per country along the years?

plot_hist_countries (ind, df_hist, quo(unemp), "unemp", -1)

plot_hist_countries (ind, df_hist, quo(emp_vuln), "emp_vuln", -1)

There is no oscillation pattern of unemployment and vulnerable work among the countries.

Generally, the unemployment level fluctuates over the years in each country. Bosnia and North Macedonia have the worst unemployment rates in Europe, West Bank and Gaza and Armenia in Asia, South Africa and Lesotho in Africa, Sta Lucia and St Vincent and the Grenadines in North America.

Regarding the vulnerable unemployment, in some countries, there has been no evolution of this indicator along the years, although in the graphic below we can notice a decrease in this kind of employment.

How have evolved unemployment and vulnerable employment per continent along the years?

hot_map (ind, df_cont, quo(unemp), "unemp", -1)

hot_map (ind, df_cont, quo(emp_vuln), "emp_vuln", -1)

Since the 1990s, the unemployment rate in the Middle East and North Africa has been high and in East Asia & Pacifica low. In the grahic above, it is possible to identify the crises of 2008 and 2009 in North America.

Analyzing the vulnerable employment in the world and in the continents, in general, it has reduced. Except in Latin America & Caribbean where it increases in recent years.

Extra Analises - Lend and Borrowing (as a % of GDP)

Which of the countries have the highest net borrowing (as a % of GDP)?

map_indicator_diverging (ind, df_fill, quo (lend_bor),"lend_bor", -1)

top_countries_min (ind, education, quo(lend_bor),"lend_bor")

The higher the unemployment the higher the poverty?

correlation (ind, df_fill, quo(unemp), quo(pov_ratio), "unemp", "pov_ratio")

The higher the vulnerable employment the higher the poverty?

correlation (ind, df_fill, quo(emp_vuln), quo(pov_ratio), "emp_vuln", "pov_ratio")

These variables have a good correlation.

The lower the education the higher the poverty?

correlation (ind, df_fill, quo(out_sch_child), quo(pov_ratio), "out_sch_child", "pov_ratio")

Is a more educated society more or less equal?


correlation (ind, df_fill, quo(ineq_10), quo(out_sch_child), "ineq_10", "out_sch_child")

Is a more poverty society more or less equal?

correlation (ind, df_fill, quo(ineq_10), quo(pov_ratio), "ineq_10", "pov_ratio")

Specific Graphics

Limits - upper and lower - Income Inequality Analysis

How much difference in income has the richest 10% of the population compared to the poorest? Where are these differences most discrepant?

        # height=10/70

# Plotting the Income inequality graph 

income10 %>%
slice_max(ineq_10, n = 40)%>%
ggplot (aes (x= values,  y = reorder(country_name, ineq_10, max), color = indicator))+
  geom_point()+
  scale_color_manual (values = c("deepskyblue4", "firebrick"), labels = c("Income by highest 10%", "Income by lowest 10%"))+
  theme(text = element_text(family = "Calibri", size = 50))+
  geom_line(aes(group = country_name), color = "grey50")+
  labs (title = "Income share held by lowest 10% and higher 10%", subtitle= "ordering by percentage of difference between the higher 10% and the lower 10%",x = "income share held by lowest 10% and higher 10%", y = "Countries", caption = "Latest data between the years 2010 to 2020")+
  theme_classic()+
  theme(panel.background = element_rect(fill = "gray95"))+
  coord_cartesian(xlim = c(0,60))+
  #theme( panel.grid.major.y = element_line(linetype = "dashed", color = "lightgray"))+
  theme(panel.border = element_rect(color='gray50', fill = NA))+
  geom_text (aes(label = values), , vjust = -1)+ #nudge_y=.3
  geom_label (aes (x=60,label = sprintf("%.1f%%", ineq_10)), color = "black")+
  theme(text = element_text(size = 20))

  #facet_wrap ('continent', scales = 'free_y')

South Africa is the country with the greatest percentage difference between the income share held by higher 10% and lowest 10%, followed by Namibia and Zambia.

The 10% of the population with the highest disposable income in South Africa received 55 times as much income as the 10% with the lowest disposable income.

Limits - upper and lower by continet - Income Inequality Analysis by continent


# Plotting the Income inequality graph facet_wrap by continent

income10%>%
  
ggplot (aes (x= values,  y = reorder(country_name, ineq_10, max), color = indicator))+
  geom_point()+
  scale_color_manual (values = c("deepskyblue4", "firebrick"), labels = c("Income by highest 10%", "Income by lowest 10%"))+
  theme(text = element_text(family = "Calibri", size = 50))+
  geom_line(aes(group = country_name), color = "grey50")+
   labs (title = "Income share held by lowest 10% and higher 10%", subtitle= "ordering by percentage of difference between the higher 10% and the lower 10%",x = "income share held by lowest 10% and higher 10%", y = "Countries", caption = "Latest data between the years 2010 to 2020")+
  theme_classic()+
  theme(panel.background = element_rect(fill = "gray95"))+
  coord_cartesian(xlim = c(0,65))+
  #theme( panel.grid.major.y = element_line(linetype = "dashed", color = "lightgray"))+
  theme(panel.border = element_rect(color='gray50', fill = NA))+
  geom_text (aes (label = values), vjust = -1)+
  geom_label (aes (x=60,label = sprintf("%.1f%%", ineq_10)), color = "black")+
  theme(text = element_text(size = 15))+
  facet_wrap ('continent', scales = 'free_y')

NA

Grifsky - Density - Quintiles - Including the income share held by quintiles of population

How much difference in income has the richest 20% of the population compared to the poorest 20% and to the other quintiles?



income20%>%
#slice_max(ineq_20, n = 80)%>%
ggplot(aes(x=values, y= reorder(country_name, ineq_20, max), fill = factor(stat(desc(quantile))))) +
  stat_density_ridges(
    geom = "density_ridges_gradient", calc_ecdf = TRUE,
    quantiles = 5, quantile_lines = TRUE
  ) +
   labs (title = "Income share held by population", subtitle= "ordering by percentage of difference between the higher 20% and the lower 20%", x = "income share held %", caption = "Latest data between the years 2010 to 2020")+
   theme(text = element_text(size = 25))+
   scale_fill_viridis_d(name = "Quintiles", option = "C")

The graphic above show the: Income share held by lowest 20% (the poorest 20%) Income share held by 2nd quintile 20% - 40% Income share held by 3rd quintile 40% - 60% Income share held by 4th quintile 60% - 80% Income share held by 5th quintile 80% - 100% (the richest 20%)

It serves to give us an idea of the inequality among the population.

Animated Correlation

This code generates a annimated graph with the correlation between 2 variables along the years

df_fields<- ind
df1<- df_fill_hist
indicator1 <-quo(out_sch_child)
indicator2 <- quo(pov_ratio)
ind1 <- "out_sch_child"
ind2 <- "pov_ratio"

# Text for title
series1 <- subset (df_fields, indicator==ind1, select= "series")
unit1 <- subset (df_fields, indicator==ind1, select= "unit")
series2 <- subset (df_fields, indicator==ind2, select= "series")
unit2 <- subset (df_fields, indicator==ind2, select= "unit")

lab_x <- paste (series1, unit1)
lab_y <- paste (series2, unit2)
lab_title <- paste (lab_x, "x", lab_y, "along the years")
  
df1%>%
  drop_na (!!indicator1, !!indicator2)
 # filter (continent == "Asia")

p<- ggplot (df1, aes (x= !!indicator1, y= !!indicator2, color = country_name, size = pop))+
  geom_point(alpha = 0.7, show.legend = FALSE)+
  scale_colour_discrete()+
  scale_size(range = c(2, 12)) +
  labs (title = "Year: {frame_time}", x=lab_x, y = lab_y, caption = "Latest data between the years 2010 to 2020")+
  facet_wrap ('continent', scales = 'free')+
  transition_time (year)+ # animation
  ease_aes('linear')

animate(p, renderer = gifski_renderer())
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpOYW1lOiBSYWNoZWwgRmFudGkgQ29lbGhvIExpbWENCm91dHB1dDoNCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0DQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBkZl9wcmludDogcGFnZWQNCkRhdGFiYXNlOiBXb3JsZCBEZXZlbG9wbWVudCBJbmRpY2F0b3JzfCBEYXRhQmFua2RhdGFiYW5rLndvcmxkYmFuay5vcmcNCi0tLQ0KDQojIFByZWxpbWluYXJpZXMNCg0KYGBge3J9DQoNCmxpYnJhcnkgKHRpZHl2ZXJzZSkNCmxpYnJhcnkgKGRwbHlyKQ0KbGlicmFyeSAoc2YpDQpsaWJyYXJ5IChybmF0dXJhbGVhcnRoKQ0KbGlicmFyeSAodmlyaWRpcykNCmxpYnJhcnkgKGdnYW5pbWF0ZSkNCmxpYnJhcnkgKGdpZnNraSkNCmxpYnJhcnkgKGdncmlkZ2VzKQ0KDQoNCmBgYA0KDQojIERhdGEgcHJlcGFyYXRpb24NClNvdXJjZTogV29ybGQgRGV2ZWxvcG1lbnQgSW5kaWNhdG9yczogDQogICAgICAgIGh0dHBzOi8vZGF0YWJhbmsud29ybGRiYW5rLm9yZy9zb3VyY2Uvd29ybGQtZGV2ZWxvcG1lbnQtaW5kaWNhdG9ycw0KICAgICAgICBTZXJpZXMgcmVsYXRlZCB0byBlY29ub215LCBlZHVjYXRpb24sIGVudmlyb25tZW50LCBoZWFsdGgsIGxhYm9yLCBwb3ZlcnR5IGFuZCBwdWJsaWMgc2VjdG9yDQoNCg0KYGBge3J9DQojIFJlYWRpbmcgZmlsZXMgIA0KIyB3ZGkgPC0gd29ybGQgZGV2ZWxvcG1lbnQgaW5kaWNhdG9ycyANCiMgaW5kIDwtIGluZGljYXRvcnMgc2VsZWN0ZWQNCiMgZGZfY29udCA8LSBtYWluIGluZGljYXRvcnMgY2FsY3VsYXRlZCBieSBjb250aW5lbnQNCiMgd29ybGQgPC0gd29ybGQgYmFzaWMgaW5kaWNhdG9ycw0KDQp3ZGkgPC0gcmVhZC5jc3YgKCIuL2RhdGEvd2RpLmNzdiIsIGhlYWRlciA9IFRSVUUsIHNlcCA9ICIsIiwgbmE9Ii4uIikNCmluZCA8LSByZWFkLmNzdiAoIi4vZGF0YS9pbmRpY2F0b3JzX3NlbGVjdGVkLmNzdiIsIGhlYWRlciA9IFRSVUUsIHNlcCA9ICI7IiwgbmE9IiIpDQpkZl9jb250IDwtIHJlYWQuY3N2ICgiLi9kYXRhL2luZGljYXRvcnNfYnlfY29udGluZW50LmNzdiIsIGhlYWRlciA9IFRSVUUsIHNlcCA9ICIsIiwgbmE9Ii4uIiwgY29sLm5hbWVzID0gYygieWVhciIsICJ5ZWFyX2NvZGUiLCAiY29udGluZW50IiwgImNvbnRpbmVudF9jb2RlIiwgInVuZW1wIiwgImVtcF92dWxuIiwgIm91dF9zY2hfYWRvIiwgIm91dF9zY2hfY2hpbGQiLCAicG92X3JhdGlvIikpDQoNCmBgYA0KDQpgYGB7cn0NCiMgRXh0cmFjdGluZyB0aGUgc2VsZWN0ZWQgaW5kaWNhdG9ycyBpbnRvIHRoZSBkYXRhIGZyb20gdGhlIHdvcmxkIGJhbmsgZGF0YWJhc2UsIGpvaW5pbmcgdGhlIDIgdGFibGVzDQojIFRyYW5zZm9ybWluZyB0aGUgY29sdW1ucyB3aXRoIHRoZSB5ZWFycyBpbiByb3dzICh1bmRlciB0aGUgY29sdW1uIHllYXIpDQojIENoYW5naW5nIHRoZSBmb3JtYXQgb2YgdGhlIGNvbHVtbiB5ZWFyIGZyb20gWDE5NzEuLllSMTk3MS4gdG8gMTk3MQ0KDQoNCmRmIDwtIGlubmVyX2pvaW4gKHdkaSwgaW5kLCBieSA9IGMoIsOvLi5TZXJpZXMuTmFtZSIgPSAic2VyaWVzX25hbWUiKSkNCmRmIDwtIHBpdm90X2xvbmdlciAoZGYsICdYMTk3MS4uWVIxOTcxLic6ICdYMjAyMC4uWVIyMDIwLicsIG5hbWVzX3RvPSd5ZWFyJywgdmFsdWVzX3RvPSd2YWx1ZXMnKSANCmRmIDwtIG11dGF0ZSAoZGYsIHllYXIgPSBhcy5pbnRlZ2VyKHN0cl9zdWIoeWVhciwgc3RhcnQgPSAyLCBlbmQgPSA1KSkpDQoNCmBgYA0KDQpgYGB7cn0NCiMgUmVuYW1pbmcgc29tZSBjb2x1bW5zIGFuZCBrZWVwaW5nIG9ubHkgdGhlIGRhdGEgd2hpY2ggaW50ZXJlc3QgdXMNCiMgVHJhbnNmb3JtaW5nIGVhY2ggaW5kaWNhdG9yIGluIGNvbHVtbnMgICh1bmRlciB0aGUgY29sdW1uIHllYXIpDQoNCiNjb2xuYW1lcyAoZGYpDQpkZjwtIHJlbmFtZShkZiwgY291bnRyeV9uYW1lID0gQ291bnRyeS5OYW1lLCBjb3VudHJ5X2NvZGUgPSBDb3VudHJ5LkNvZGUpDQpkZjwtIHNlbGVjdCAoZGYsIGluZGljYXRvciwgY291bnRyeV9uYW1lLCBjb3VudHJ5X2NvZGUsIHllYXIsIHZhbHVlcykNCmRmIDwtIHBpdm90X3dpZGVyIChkZiwgbmFtZXNfZnJvbSA9ICJpbmRpY2F0b3IiLCB2YWx1ZXNfZnJvbSA9ICJ2YWx1ZXMiKQ0KYGBgDQoNCg0KYGBge3J9DQojIEluY2x1ZGluZyBzb21lIGNvbHVtbnMgdG8gYW5hbHl6ZSBpbmVxdWFsaXR5DQojIEluY2x1ZGluZyBhIGNvbHVtbiB3aXRoIHRoZSBwZXJjZW50YWdlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgaW5jb21lIHNoYXJlIGhlbGQgYnkgaGlnaGVzdCAxMCUgYW5kIGluY29tZSBzaGFyZSBoZWxkIGJ5IGxvd2VzdCAxMCUNCiMgSW5jbHVkaW5nIGEgY29sdW1uIHdpdGggdGhlIHBlcmNlbnRhZ2UgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBpbmNvbWUgc2hhcmUgaGVsZCBieSBoaWdoZXN0IDIwJSBhbmQgaW5jb21lIHNoYXJlIGhlbGQgYnkgbG93ZXN0IDIwJQ0KDQpkZjwtIGRmICU+JQ0KbXV0YXRlIChpbmVxXzEwID0gaW5jX2hpZ2gxMC9pbmNfbG93MTAgLTEpJT4lDQptdXRhdGUgKGluZXFfMjAgPSBpbmNfaGlnaDIwL2luY19sb3cyMCAtMSkNCg0KYGBgDQoNCmBgYHtyfQ0KIyBXcml0aW5nIGRhdGEgaW4gYSB0YWJsZQ0Kd3JpdGUudGFibGUoZGYsIGZpbGU9ICJkZi5jc3YiKQ0KYGBgDQoNCiMgR2VvcmVmZXJlbmNpbmcgdGhlIGRhdGEgDQoNCmBgYHtyfQ0KZGYgPC0gcmVhZC50YWJsZSgiZGYuY3N2IikNCmBgYA0KDQpgYGB7cn0NCiMgT2J0YWluaW5nIHRoZSBnZW9yZWZlcmVuY2VkIGRhdGFiYXNlIGZvciB0aGUgY291bnRyaWVzIA0KDQpjb3VudHJpZXMgPC0gbmVfY291bnRyaWVzKHNjYWxlID0gImxhcmdlIiwgcmV0dXJuY2xhc3MgPSAic2YiKQ0KY29sbmFtZXMgKGNvdW50cmllcykNCg0KYGBgDQoNCmBgYHtyfQ0KIyBTZWxlY3Rpbmcgb25seSB0aGUgY29sdW1ucyBvZiBpbnRlcmVzdA0KDQpjb3VudHJpZXMgPC0gY291bnRyaWVzJT4lDQpzZWxlY3QgKG5hbWUsIGNvbnRpbmVudCwgYWRtMF9hMywgaXNvX2EzLCBlY29ub215LCBpbmNvbWVfZ3JwLCBnZW9tZXRyeSkNCg0KIyBPdGhlciBjb2x1bW5zOiB0eXBlLCBhZG1pbiwgcmVnaW9uX3VuLCBzdWJyZWdpb24sIHJlZ2lvbl93YiwgcG9wX2VzdCwgcG9wX3JhbmssIGdkcF9tZF9lc3QsIHBvcF95ZWFyLCBsYXN0Y2Vuc3VzLCAgZ2RwX3llYXIgDQpgYGANCg0KYGBge3J9DQojIEFuYWx5emluZyB3aGljaCBjb2x1bW5zIHdpbGwgbm90IG1hdGNoIGluIGpvaW5pbmcgYW5kIHRyZWF0aW5nIHRoZW0NCg0Kbm9fbWVldCA8LWFudGlfam9pbihkZiwgY291bnRyaWVzLCBieSA9IGMoICJjb3VudHJ5X2NvZGUiPSAiaXNvX2EzIikpIA0Kbm9fbWVldCU+JQ0KICBkaXN0aW5jdChjb3VudHJ5X2NvZGUpDQoNCmNvdW50cmllczwtIGNvdW50cmllcyU+JQ0KbXV0YXRlKGNvZCA9IGNhc2Vfd2hlbigNCiAgICAgICAgIGFkbTBfYTM9PSdGUkEnfiAnRlJBJywNCiAgICAgICAgIGFkbTBfYTM9PSdLT1MnfiAnWEtYJywNCiAgICAgICAgIGFkbTBfYTM9PSdOT1InfiAnTk9SJywNCiAgICAgICAgIGFkbTBfYTM9PSdHR1knfiAnQ0hJJywNCiAgICAgICAgIFRSVUUgfiBpc29fYTMNCiAgICAgICAgICkNCikNCmNvdW50cmllcw0KYGBgDQoNCg0KYGBge3J9DQojIGpvaW5pbmcgdGhlIG1haW4gZGF0YSBmcmFtZSB3aXRoIHRoZSB0YWJsZSBjb250YWluaW5nIHRoZSBnZW9ncmFwaGljIGluZm9ybWF0aW9uIG9mIHRoZSBjb3VudHJpZXMNCiMgdmVyaWZ5aW5nIHRoZSBudW1iZXIgb2YgbGluZXMgYW5kIGlmIGFsbCByb3dzIG1hdGNoZWQgYXBwcm9wcmlhdGVseSwgdXNpbmcNCiMgYW50aV9qb2luKCkgLSByZXR1cm4gYWxsIHJvd3MgZnJvbSB4IHdoZXJlIHRoZXJlIGFyZSBub3QgbWF0Y2hpbmcgdmFsdWVzIGluIHksIGtlZXBpbmcganVzdCBjb2x1bW5zIGZyb20geA0KDQpkZl9nZW8gPC0gbGVmdF9qb2luIChkZiwgY291bnRyaWVzLCBieSA9IGMoICJjb3VudHJ5X2NvZGUiPSAiY29kIikpDQpgYGANCg0KDQpgYGB7cn0NCiMgV3JpdGluZyBkYXRhIGluIGEgdGFibGUNCiMgd3JpdGUudGFibGUoZGZfZ2VvLCBmaWxlPSAiZGZfZ2VvLmNzdiIpDQpgYGANCg0KIyBQcmVwYXJpbmcgc29tZSBkYXRhc2V0LCBhY2NvcmRpbmcgdG8gdGhlIHRoZW1lDQoNCmBgYHtyIGRhdGFzZXRzfQ0KDQojIEV4dHJhY3RpbmcgdGhlIG1haW4gaW5kaWNhdG9ycyBhbmQgZmlsbCB0aGUgYmxhbmsgdmFsdWVzIHdpdGggdGhlIG1vcmUgcmVjZW50IA0KDQpkZl9maWxsIDwtIGRmX2dlbyAlPiUNCnNlbGVjdCAoY291bnRyeV9uYW1lLCBjb3VudHJ5X2NvZGUsIGNvbnRpbmVudCwgeWVhciwgcG9wLCBwb3ZfcmF0aW8sIG91dF9zY2hfY2hpbGQsIHVuZW1wLCBlbXBfdnVsbiwgaW5lcV8xMCwgaW5lcV8yMCwgaW5jX2xvdzEwLCBpbmNfbG93MjAsIGluY19sb3cyMF80MCwgaW5jX2xvdzQwXzYwLCBpbmNfbG93NjBfODAsIGluY19oaWdoMTAsIGluY19oaWdoMjAsIHBvcF9zbHVtLCBsZW5kX2JvciwgYWNjX3dhdCwgYWNjX2VsZSwgYWNjX3NhbiwgY2hpbGRfbW9ydCwgZ2VvbWV0cnkpJT4lDQojIGZpbHRlciAoeWVhcj09IDIwMTcpIGFzIA0KIyBjb3VudChpcy5uYShwb3ZfcmF0aW8pKSAjVmVyaWZ5IHRoZSBxdWFudGl0eSBvZiBOQSBkYXRhDQojIEFzIHRoZXJlIGFyZSBtYW55IGNvdW50cmllcyB3aXRob3V0IGRhdGEsIEkgd2lsbCBmaWxsIHdpdGggZGF0YSBmcm9tIDIwMTAgdG8gMjAyMCAoaW5jbHVkaW5nIHRoZSBsYXRlc3QgZGF0YSkNCmZpbHRlciAoeWVhcj49IDIwMTApICU+JQ0KZ3JvdXBfYnkoY291bnRyeV9uYW1lKSAlPiUNCmZpbGwocG9wOmNoaWxkX21vcnQpICU+JQ0KdW5ncm91cCAoKSAgJT4lDQpmaWx0ZXIgKHllYXI9PSAyMDIwKQ0KDQoNCiMgY3JlYXRpbmcgc3BlY2lmaWMgdGFibGVzIGZvciBlYWNoIGFuYWx5c2UNCg0KcG92ZXJ0eTwtIGRmX2ZpbGwlPiUNCiAgZHJvcF9uYSAoInBvdl9yYXRpbyIpDQoNCmVkdWNhdGlvbjwtIGRmX2ZpbGwlPiUNCiAgZHJvcF9uYSAoIm91dF9zY2hfY2hpbGQiKQ0KDQppbmVxdWFsaXR5PC0gZGZfZmlsbCU+JQ0KICBkcm9wX25hICgiaW5lcV8xMCIpDQoNCnVuZW1wbG95bWVudDwtIGRmX2ZpbGwlPiUNCiAgZHJvcF9uYSAoInVuZW1wIikNCg0KZW1wX3Z1bG5lcmFibGU8LSBkZl9maWxsJT4lDQogIGRyb3BfbmEgKCJlbXBfdnVsbiIpDQoNCmluY29tZTEwIDwtIGRmX2ZpbGwgJT4lICMgc2VsZWN0aW5nIGRhdGEgcmVsYXRlZCB0byBpbmNvbWUgYW5kIGluZXF1YWxpdHkNCiAgc2VsZWN0IChjb3VudHJ5X25hbWUsIGNvbnRpbmVudCwgeWVhciwgaW5lcV8xMCwgaW5jX2xvdzEwLCBpbmNfaGlnaDEwKSAlPiUNCiAgZHJvcF9uYSAoaW5jX2xvdzEwLCBpbmNfaGlnaDEwKSAlPiUNCiAgcGl2b3RfbG9uZ2VyICgiaW5jX2xvdzEwIjogImluY19oaWdoMTAiLCBuYW1lc190byA9ICJpbmRpY2F0b3IiLCB2YWx1ZXNfdG8gPSAidmFsdWVzIikNCg0KaW5jb21lMjAgPC0gZGZfZmlsbCAlPiUgIyBzZWxlY3RpbmcgZGF0YSByZWxhdGVkIHRvIGluY29tZSBhbmQgaW5lcXVhbGl0eSAtIHF1aW50aWxlcw0KICBzZWxlY3QgKGNvdW50cnlfbmFtZSwgY29udGluZW50LCB5ZWFyLCBpbmVxXzIwLCBpbmNfbG93MjAsIGluY19sb3cyMF80MCwgaW5jX2xvdzQwXzYwLCBpbmNfbG93NjBfODAsIGluY19oaWdoMjApICU+JQ0KICBkcm9wX25hIChpbmNfbG93MjAsIGluY19sb3cyMF80MCwgaW5jX2xvdzQwXzYwLCBpbmNfbG93NjBfODAsIGluY19oaWdoMjApICU+JQ0KICBwaXZvdF9sb25nZXIgKCJpbmNfbG93MjAiOiAiaW5jX2hpZ2gyMCIsIG5hbWVzX3RvID0gImluZGljYXRvciIsIHZhbHVlc190byA9ICJ2YWx1ZXMiKQ0KDQoNCmRmX2ZpbGxfaGlzdCA8LSBkZl9nZW8gJT4lICMgc2VsZWN0aW5nIGhpc3RvcmljIGRhdGEgYW5kIGZpbGwgdGhlIG51bGwgdmFsdWVzIChmb3IgdXNlIGluIHRoZSBhbmltYXRlZCBncmFwaGljKQ0Kc2VsZWN0IChjb3VudHJ5X25hbWUsIGNvbnRpbmVudCwgeWVhciwgcG9wLCBwb3ZfcmF0aW8sIG91dF9zY2hfY2hpbGQsIHVuZW1wLCBlbXBfdnVsbiwgYWNjX3dhdCwgYWNjX2VsZSwgYWNjX3NhbiwgY2hpbGRfbW9ydCklPiUNCmZpbHRlciAoeWVhcj49IDE5ODApICU+JQ0KZ3JvdXBfYnkoY291bnRyeV9uYW1lKSAlPiUNCmZpbGwocG9wOmNoaWxkX21vcnQpICU+JQ0KdW5ncm91cCAoKSU+JQ0KZmlsdGVyICh5ZWFyPj0gMTk5MCkNCiNmaWx0ZXIgKHllYXI9PSAxOTkwIHwgeWVhcj09IDIwMDAgfCB5ZWFyPT0gMjAyMCkNCg0KZGZfaGlzdCA8LSBkZl9nZW8gJT4lICMgc2VsZWN0aW5nIGhpc3RvcmljIGRhdGEgd2l0aG91dCBhbnkgZmlsbA0Kc2VsZWN0IChjb3VudHJ5X25hbWUsIGNvbnRpbmVudCwgeWVhciwgcG92X3JhdGlvLCBvdXRfc2NoX2NoaWxkLCB1bmVtcCwgZW1wX3Z1bG4sIHBvcCkNCiNkcm9wX25hIChwb3ZfcmF0aW8pDQoNCmBgYA0KDQoNCiMgR2VuZXJhdGluZyBtb2RlbHMgb2YgZ3JhcGhpY3MgZm9yIGFuYWx5c2VzIA0KDQojIE1hcHMgKDEpDQpgYGB7cn0NCiMgVGhpcyBmdW5jdGlvbiBnZW5lcmF0ZXMgYSBjb2xvcmVkIG1hcCwgYWNjb3JkaW5nIHRvIHRoZSByYW5raW5nIG9mIGNvdW50cmllcyBpbiBhIHNwZWNpZmljIGluZGljYXRvcg0KbWFwX2luZGljYXRvciA8LSBmdW5jdGlvbihkZl9maWVsZHMsIGRmLCBpbmRpY2F0b3IsIGluZCwgb3JpZW50YXRpb24pew0KICANCiAgIyBUZXh0IGZvciB0aXRsZQ0KICBzdWJqZWN0PC0gc3Vic2V0IChkZl9maWVsZHMsIGluZGljYXRvcj09aW5kLCBzZWxlY3Q9ICJkYXRhc2V0IikNCiAgc2VyaWVzIDwtIHN1YnNldCAoZGZfZmllbGRzLCBpbmRpY2F0b3I9PWluZCwgc2VsZWN0PSAic2VyaWVzIikNCiAgdW5pdCA8LSBzdWJzZXQgKGRmX2ZpZWxkcywgaW5kaWNhdG9yPT1pbmQsIHNlbGVjdD0gInVuaXQiKQ0KICB0aXRsZSA9IHBhc3RlIChzZXJpZXMsIHVuaXQpDQoNCiAgIyBUZXh0IGZvciBsYWJlbA0KICANCiAgaWYgKG9yaWVudGF0aW9uID09MSl7IA0KICAgIGRmMTwtIGRmJT4lDQogICAgZHJvcF9uYSAoISFpbmRpY2F0b3IpJT4lDQogICAgZ3JvdXBfYnkgKGdyb3VwID0gIGZhY3RvcihudGlsZSghIWluZGljYXRvciwgNSkpKSAlPiUNCiAgICBzdW1tYXJpc2UgKHVwcGVyID0gbWF4KCEhaW5kaWNhdG9yKSwgbG93ZXIgPSBtaW4oISFpbmRpY2F0b3IpKSAlPiUNCiAgICBtdXRhdGUobGFiZWwgPSBzdHJfYyhzcHJpbnRmKCIlLjFmIiwgbG93ZXIpLCAiIHRvICIsIHNwcmludGYoIiUuMWYiLCB1cHBlcikpKQ0KICAgICAgfQ0KICBlbHNlew0KICAgIGRmMTwtIGRmJT4lDQogICAgZHJvcF9uYSAoISFpbmRpY2F0b3IpJT4lDQogICAgZ3JvdXBfYnkgKGdyb3VwID0gIGZhY3RvcihudGlsZShkZXNjKCEhaW5kaWNhdG9yKSwgNSkpKSAlPiUNCiAgICBzdW1tYXJpc2UgKHVwcGVyID0gbWF4KCEhaW5kaWNhdG9yKSwgbG93ZXIgPSBtaW4oISFpbmRpY2F0b3IpKSAlPiUNCiAgICBtdXRhdGUgKGxhYmVsID0gc3RyX2Moc3ByaW50ZigiJS4xZiIsIGxvd2VyKSwgIiB0byAiLCBzcHJpbnRmKCIlLjFmIiwgdXBwZXIpKSkNCiAgICAgIH0NCiAgDQogICAgIyBwcmludCAoaGVhZChkZjEpKQ0KICAgIA0KICBpZiAob3JpZW50YXRpb24gPT0gMSkNCnsNCiAgZGF0YSA8LSBzdF9zZihkZikgIA0KICBnZ3Bsb3QoKSArDQogICAgZ2VvbV9zZihkYXRhPSBkYXRhLCBhZXMoZmlsbCA9IGZhY3RvcihudGlsZSgoISFpbmRpY2F0b3IpLDUpKSkpICsNCiAgICBzY2FsZV9maWxsX3ZpcmlkaXNfZChuYW1lID0gcGFzdGUgKHN1YmplY3QsICIoNSBudGlsZSkiKSwgbGFiZWxzID0gYyAoZGYxJGxhYmVsKSkrDQogICAgbGFicyAodGl0bGUgPSB0aXRsZSwgY2FwdGlvbiA9ICJMYXRlc3QgZGF0YSwgYmV0d2VlbiB0aGUgeWVhcnMgMjAxMCB0byAyMDIwIikrDQogICAgIyBnZW9tX3NmX3RleHQoZGF0YT1kYXRhLCBhZXMobGFiZWwgPSBzdHJfd3JhcChpbmRpY2F0b3IsIDEpKSwgc2l6ZSA9IDQpKw0KICAgIHRoZW1lX3ZvaWQoKQ0KfQ0KZWxzZQ0Kew0KICBkYXRhIDwtIHN0X3NmKGRmKQ0KICBnZ3Bsb3QoKSArDQogICAgZ2VvbV9zZihkYXRhPSBkYXRhLCBhZXMoZmlsbCA9IGZhY3RvcihudGlsZShkZXNjKCEhaW5kaWNhdG9yKSw1KSkpKSArDQogICAgc2NhbGVfZmlsbF92aXJpZGlzX2QobmFtZSA9IHBhc3RlIChzdWJqZWN0LCAiKDUgbnRpbGUpIiksIGxhYmVscyA9IGMgKGRmMSRsYWJlbCkpKw0KICAgIGxhYnMgKHRpdGxlID0gdGl0bGUsIGNhcHRpb24gPSAiTGF0ZXN0IGRhdGEsIGJldHdlZW4gdGhlIHllYXJzIDIwMTAgdG8gMjAyMCIpKw0KICAgICMgZ2VvbV9zZl90ZXh0KGRhdGE9ZGF0YSwgYWVzKGxhYmVsID0gc3RyX3dyYXAoaW5kaWNhdG9yLCAxKSksIHNpemUgPSA0KSsNCiAgICB0aGVtZV92b2lkKCkNCn0NCn0NCg0KIyBJbnB1dHMgZm9yIHRoZSBhbmFseXNlcw0KbWFwX2luZGljYXRvciAoaW5kLCBkZl9maWxsLCBxdW8ocG92X3JhdGlvKSwgInBvdl9yYXRpbyIsIC0xKQ0KDQoNCmBgYA0KDQojIE1hcHMgKDIpDQpgYGB7cn0NCiMgVGhpcyBmdW5jdGlvbiBnZW5lcmF0ZXMgYSBjb2xvcmVkIG1hcCBvZiBvbmUgY29udGluZW50LCBhY2NvcmRpbmcgdG8gdGhlIHJhbmtpbmcgb2YgY291bnRyaWVzIGluIGEgc3BlY2lmaWMgaW5kaWNhdG9yDQptYXBfaW5kaWNhdG9yX2NvbnRpbmVudCA8LSBmdW5jdGlvbihjb250LCBkZl9maWVsZHMsIGRmLCBpbmRpY2F0b3IsIGluZCwgb3JpZW50YXRpb24pew0KICANCiAgIyBUZXh0IGZvciB0aXRsZQ0KICBzdWJqZWN0PC0gc3Vic2V0IChkZl9maWVsZHMsIGluZGljYXRvcj09aW5kLCBzZWxlY3Q9ICJkYXRhc2V0IikNCiAgc2VyaWVzIDwtIHN1YnNldCAoZGZfZmllbGRzLCBpbmRpY2F0b3I9PWluZCwgc2VsZWN0PSAic2VyaWVzIikNCiAgdW5pdCA8LSBzdWJzZXQgKGRmX2ZpZWxkcywgaW5kaWNhdG9yPT1pbmQsIHNlbGVjdD0gInVuaXQiKQ0KICB0aXRsZSA9IHBhc3RlIChzZXJpZXMsIHVuaXQpDQoNCiAgIyBUZXh0IGZvciBsYWJlbA0KICANCiAgaWYgKG9yaWVudGF0aW9uID09MSl7IA0KICAgIGRmMTwtIGRmJT4lDQogICAgZmlsdGVyIChjb250aW5lbnQ9PWNvbnQpJT4lDQogICAgZHJvcF9uYSAoISFpbmRpY2F0b3IpJT4lICAgDQogICAgZ3JvdXBfYnkgKGdyb3VwID0gIGZhY3RvcihudGlsZSghIWluZGljYXRvciwgNSkpKSAlPiUNCiAgICBzdW1tYXJpc2UgKHVwcGVyID0gbWF4KCEhaW5kaWNhdG9yKSwgbG93ZXIgPSBtaW4oISFpbmRpY2F0b3IpKSAlPiUNCiAgICBtdXRhdGUobGFiZWwgPSBzdHJfYyhzcHJpbnRmKCIlLjFmIiwgbG93ZXIpLCAiIHRvICIsIHNwcmludGYoIiUuMWYiLCB1cHBlcikpKQ0KICAgICAgfQ0KICBlbHNlew0KICAgIGRmMTwtIGRmJT4lDQogICAgZmlsdGVyIChjb250aW5lbnQ9PWNvbnQpJT4lDQogICAgZHJvcF9uYSAoISFpbmRpY2F0b3IpJT4lDQogICAgZ3JvdXBfYnkgKGdyb3VwID0gIGZhY3RvcihudGlsZShkZXNjKCEhaW5kaWNhdG9yKSwgNSkpKSAlPiUNCiAgICBzdW1tYXJpc2UgKHVwcGVyID0gbWF4KCEhaW5kaWNhdG9yKSwgbG93ZXIgPSBtaW4oISFpbmRpY2F0b3IpKSAlPiUNCiAgICBtdXRhdGUgKGxhYmVsID0gc3RyX2Moc3ByaW50ZigiJS4xZiIsIGxvd2VyKSwgIiB0byAiLCBzcHJpbnRmKCIlLjFmIiwgdXBwZXIpKSkNCiAgICAgIH0NCiAgDQogICAgI3ByaW50IChoZWFkKGRmMSkpDQogICAgDQogICANCiAgaWYgKG9yaWVudGF0aW9uID09IDEpDQp7DQogICAgZGF0YSA8LSBzdF9zZihkZiklPiUNCiAgICBmaWx0ZXIgKGNvbnRpbmVudD09Y29udCkNCiAgZ2dwbG90KCkgKw0KICAgIGdlb21fc2YoZGF0YT0gZGF0YSwgYWVzKGZpbGwgPSBmYWN0b3IobnRpbGUoKCEhaW5kaWNhdG9yKSw1KSkpKSArDQogICAgc2NhbGVfZmlsbF9icmV3ZXIgKG5hbWUgPSBwYXN0ZSAoc3ViamVjdCwgIig1IG50aWxlKSIpLCBsYWJlbHMgPSBjIChkZjEkbGFiZWwpLCBkaXJlY3Rpb249LTEpKw0KICAgICMgZ2VvbV9zZl90ZXh0KGRhdGE9IGRhdGEsIGFlcyhsYWJlbCA9IGNvdW50cnlfY29kZSksIHNpemUgPSA0KSsNCiAgICAjIGdlb21fc2ZfdGV4dChkYXRhPWRhdGEsIGFlcyhsYWJlbCA9IHN0cl93cmFwKCEhaW5kaWNhdG9yLCAxKSksIHNpemUgPSAzLCBmb250ZmFjZSA9ICJib2xkIikrDQogICAgbGFicyAodGl0bGUgPSB0aXRsZSwgY2FwdGlvbiA9ICJMYXRlc3QgZGF0YSwgYmV0d2VlbiB0aGUgeWVhcnMgMjAxMCB0byAyMDIwIikrDQogICAgdGhlbWVfdm9pZCgpDQp9DQplbHNlDQp7DQogICAgZGF0YSA8LSBzdF9zZihkZiklPiUNCiAgICBmaWx0ZXIgKGNvbnRpbmVudD09Y29udCkNCiAgICBnZ3Bsb3QoKSArDQogICAgZ2VvbV9zZihkYXRhPSBkYXRhLCBhZXMoZmlsbCA9IGZhY3RvcihudGlsZShkZXNjKCEhaW5kaWNhdG9yKSw1KSkpKSArDQogICAgc2NhbGVfZmlsbF9icmV3ZXIgKG5hbWUgPSBwYXN0ZSAoc3ViamVjdCwgIig1IG50aWxlKSIpLCBsYWJlbHMgPSBjIChkZjEkbGFiZWwpLCBkaXJlY3Rpb249LTEpKw0KICAgICMgZ2VvbV9zZl90ZXh0KGRhdGE9IGRhdGEsIGFlcyhsYWJlbCA9IGNvdW50cnlfY29kZSksIHNpemUgPSA0KSsNCiAgICAjIGdlb21fc2ZfdGV4dChkYXRhPWRhdGEsIGFlcyhsYWJlbCA9IHN0cl93cmFwKCEhaW5kaWNhdG9yLCAxKSksIHNpemUgPSAzLCBmb250ZmFjZSA9ICJib2xkIikrDQogICAgbGFicyAodGl0bGUgPSB0aXRsZSwgY2FwdGlvbiA9ICJMYXRlc3QgZGF0YSwgYmV0d2VlbiB0aGUgeWVhcnMgMjAxMCB0byAyMDIwIikrDQogICAgdGhlbWVfdm9pZCgpDQp9DQp9DQoNCm1hcF9pbmRpY2F0b3JfY29udGluZW50ICgiQWZyaWNhIiwgaW5kLCBkZl9maWxsLCBxdW8ocG92X3JhdGlvKSwgInBvdl9yYXRpbyIsIC0xKQ0KYGBgDQoNCiMgTWFwcyAoMykNCmBgYHtyfQ0KIyBUaGlzIGZ1bmN0aW9uIGdlbmVyYXRlcyBhIG1hcCB3aXRoIGRpdmVyZ2luZyBjb2xvcnMsIGFjY29yZGluZyB0byB0aGUgdmFsdWVyIG9mIGEgc3BlY2lmaWMgaW5kaWNhdG9yDQptYXBfaW5kaWNhdG9yX2RpdmVyZ2luZyA8LSBmdW5jdGlvbihkZl9maWVsZHMsIGRmLCBpbmRpY2F0b3IsIGluZCwgb3JpZW50YXRpb24pew0KICANCiBsaWJyYXJ5KCJjb2xvcnNwYWNlIikNCiAgDQogICMgVGV4dCBmb3IgdGl0bGUNCiAgc3ViamVjdDwtIHN1YnNldCAoZGZfZmllbGRzLCBpbmRpY2F0b3I9PWluZCwgc2VsZWN0PSAiZGF0YXNldCIpDQogIHNlcmllcyA8LSBzdWJzZXQgKGRmX2ZpZWxkcywgaW5kaWNhdG9yPT1pbmQsIHNlbGVjdD0gInNlcmllcyIpDQogIHVuaXQgPC0gc3Vic2V0IChkZl9maWVsZHMsIGluZGljYXRvcj09aW5kLCBzZWxlY3Q9ICJ1bml0IikNCiAgdGl0bGUgPSBwYXN0ZSAoc2VyaWVzLCB1bml0KQ0KDQogIGlmIChvcmllbnRhdGlvbiA9PSAxKQ0Kew0KICBkYXRhIDwtIHN0X3NmKGRmKSAgDQogIGdncGxvdCgpICsNCiAgICBnZW9tX3NmKGRhdGE9IGRhdGEsIGFlcyhmaWxsID0gISFpbmRpY2F0b3IpKSArDQogICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnRuIChjb2xvcnMgPSBjKCJkYXJrcmVkIiwgInJlZCIsICJ3aGl0ZSIsICJibHVlIiwgImRhcmtibHVlIiksIGJyZWFrcyA9IGMgKC0zMCwtMTAsMCwxMCwzMCksIG5hLnZhbHVlID0gImdyZXk1MCIpKw0KICAgIGxhYnMgKHRpdGxlID0gdGl0bGUsIGNhcHRpb24gPSAiTGF0ZXN0IGRhdGEsIGJldHdlZW4gdGhlIHllYXJzIDIwMTAgdG8gMjAyMCIpKw0KICAgICMgZ2VvbV9zZl90ZXh0KGRhdGE9ZGF0YSwgYWVzKGxhYmVsID0gc3RyX3dyYXAoaW5kaWNhdG9yLCAxKSksIHNpemUgPSA0KSsNCiAgICB0aGVtZV92b2lkKCkNCn0NCmVsc2UNCnsNCiAgZGF0YSA8LSBzdF9zZihkZikNCiAgZ2dwbG90KCkgKw0KICAgIGdlb21fc2YoZGF0YT0gZGF0YSwgYWVzKGZpbGwgPSAhIWluZGljYXRvcikpICsNCiAgICBzY2FsZV9maWxsX2dyYWRpZW50biAoY29sb3JzID0gYyAoImRhcmtyZWQiLCAicmVkIiwgIndoaXRlIiwgImJsdWUiLCAiZGFya2JsdWUiKSwgYnJlYWtzID0gYyAoLTMwLC0xMCwwLDEwLDMwKSwgbmEudmFsdWUgPSAiZ3JleTUwIikrDQogICAgbGFicyAodGl0bGUgPSB0aXRsZSwgY2FwdGlvbiA9ICJMYXRlc3QgZGF0YSwgYmV0d2VlbiB0aGUgeWVhcnMgMjAxMCB0byAyMDIwIikrDQogICAgIyBnZW9tX3NmX3RleHQoZGF0YT1kYXRhLCBhZXMobGFiZWwgPSBzdHJfd3JhcChpbmRpY2F0b3IsIDEpKSwgc2l6ZSA9IDQpKw0KICAgIHRoZW1lX3ZvaWQoKQ0KfQ0KfQ0KDQojIElucHV0cyBmb3IgdGhlIGFuYWx5c2VzDQptYXBfaW5kaWNhdG9yX2RpdmVyZ2luZyAoaW5kLCBkZl9maWxsLCBxdW8obGVuZF9ib3IpLCAibGVuZF9ib3IiLCAtMSkNCg0KYGBgDQoNCiMgSGlzdG9ncmFtcw0KYGBge3J9DQojIFRoaXMgZnVuY3Rpb24gZ2VuZXJhdGUgYSBoaXN0b2dyYW0gZm9yIGEgc3BlY2lmaWMgaW5kaWNhdG9yDQpoaXN0b2dyYW0gPC0gZnVuY3Rpb24oZGZfZmllbGRzLCBkZiwgaW5kaWNhdG9yLCBpbmQpew0KDQojIEV4dHJhY3RpbmcgdGhlIGRldGFpbHMgb2YgdGhlIGZpZWxkcyBmcm9tIHRoZSBkYXRhIGZyYW1lIChuYW1lIG9mIHRoZSBzdWJqZWN0LCBpbmRpY2F0b3IgKHNlcmllcykgYW5kIHVuaXQpDQpzdWJqZWN0PC0gc3Vic2V0IChkZl9maWVsZHMsIGluZGljYXRvcj09aW5kLCBzZWxlY3Q9ICJkYXRhc2V0IikgIyBvciBpbmQlPiUgZmlsdGVyIChpbmRpY2F0b3I9PSJwb3ZfcmF0aW8iKSU+JSBzZWxlY3QgKCJkYXRhc2V0IikNCnNlcmllcyA8LSBzdWJzZXQgKGRmX2ZpZWxkcywgaW5kaWNhdG9yPT1pbmQsIHNlbGVjdD0gInNlcmllcyIpDQp1bml0IDwtIHN1YnNldCAoZGZfZmllbGRzLCBpbmRpY2F0b3I9PWluZCwgc2VsZWN0PSAidW5pdCIpDQpjb3VudHJpZXMgPC0gbGVuZ3RoKGluZGljYXRvcikNCg0KbGFiX3RpdGxlIDwtIHBhc3RlICgiIyBvZiBjb3VudHJpZXMgYWNjb3JkaW5nIHRvIHRoZSBsZXZlbCBvZiIsIHN1YmplY3QpDQpsYWJfeCA9IHBhc3RlIChzZXJpZXMsIHVuaXQpDQoNCiAgICAgIA0KZGYgJT4lDQoNCmdncGxvdCAoYWVzIChpbmRpY2F0b3IpKSsNCiAgZ2VvbV9oaXN0b2dyYW0oYnJlYWtzPXNlcSAoMCwxMDAsIGJ5ID0gMTApLCBjb2xvciA9ICJkYXJrYmx1ZSIsIGZpbGwgPSAic3RlZWxibHVlIikrDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEgKDAsIDEwMCwgYnkgPSAxMCkpKw0KICBzdGF0X2JpbihiaW53aWR0aCA9IDEwLCBnZW9tPSd0ZXh0JywgY29sb3IgPSAid2hpdGUiLCBjZW50ZXIgPSA1LCBhZXMobGFiZWw9KC4uY291bnQuLikpLCBwb3NpdGlvbj1wb3NpdGlvbl9zdGFjaygwLjUpKSsNCiAgbGFicyAodGl0bGUgPSBsYWJfdGl0bGUsIHg9bGFiX3gsIHkgPSAiIyBvZiBjb3VudHJpZXMiLCBjYXB0aW9uID0gIkxhdGVzdCBkYXRhIGJldHdlZW4gdGhlIHllYXJzIDIwMTAgdG8gMjAyMCIpKw0KICBnZW9tX3RleHQgKHggPSA4MCwgeSA9IDMwLCBsYWJlbCA9IHBhc3RlKCIjIG9mIGNvdW50cmllcyBhbmFseXplZD0iLCBjb3VudHJpZXMpKQ0KDQp9DQoNCmhpc3RvZ3JhbSAoaW5kLCBwb3ZlcnR5LCBwb3ZlcnR5JHBvdl9yYXRpbywgInBvdl9yYXRpbyIpKw0KZ2VvbV90ZXh0KHggPSA0MCwgeSA9IDUwLCBsYWJlbCA9ICIxMCBjb3VudHJpZXMgd2l0aCBtb3JlIHRoYW4gNTAlIG9mIHRoZSBwb3B1bGF0aW9uDQogICAgICAgICAgbGl2aW5nIGluIGNvbmRpdGlvbnMgb2YgZXh0cmVtZSBwb3ZlcnR5IiwgaGp1c3QgPSAwLCB2anVzdCA9IDAuNSwgY29sb3VyID0gInJlZCIsIHNpemUgPSA0KSsNCmdlb21fc2VnbWVudChhZXMoeCA9IDU1LCB5ID0gNDAsIHhlbmQgPSA1NSwgeWVuZCA9IDE1KSwgY29sb3VyPSJyZWQiLCBzaXplPTAuNSwgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuNSwgImNtIikpKSsNCg0KZ2VvbV90ZXh0KHggPSAyMCwgeSA9IDcwLCBsYWJlbCA9ICIzNSBjb3VudHJpZXMgd2l0aCBtb3JlIHRoYW4gMjAlIG9mIHRoZSBwb3B1bGF0aW9uDQogICAgICAgICAgbGl2aW5nIGluIGNvbmRpdGlvbnMgb2YgZXh0cmVtZSBwb3ZlcnR5IiwgaGp1c3QgPSAwLCB2anVzdCA9IDAuNSwgY29sb3VyID0gInJlZCIsIHNpemUgPSA0KSsNCmdlb21fc2VnbWVudChhZXMoeCA9IDI1LCB5ID0gNjAsIHhlbmQgPSAyNSwgeWVuZCA9IDE1KSwgY29sb3VyPSJyZWQiLCBzaXplPTAuNSwgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuNSwgImNtIikpKQ0KYGBgDQoNCg0KIyBDb2x1bW5zIC0gVG9wIGNvdW50cmllcw0KDQpgYGB7ciBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTV9DQoNCiMgVGhpcyBmdW5jdGlvbiBnZW5lcmF0ZSBhIGxpc3Qgd2l0aCB0aGUgcmFua2luZyBjb3VudHJpZXMgaW4gb25lIHNwZWNpZmljIGluZGljYXRvciAobWF4aW11bSkNCnRvcF9jb3VudHJpZXNfbWF4IDwtIGZ1bmN0aW9uKGRmX2ZpZWxkcywgZGYsIGluZGljYXRvciwgaW5kKXsNCiAgDQpuPTM1DQoNCiMgVGV4dCBmb3IgbGFicyAoeCwgeSBhbmQgdGl0bGUpDQpzdWJqZWN0PC0gc3Vic2V0IChkZl9maWVsZHMsIGluZGljYXRvcj09aW5kLCBzZWxlY3Q9ICJkYXRhc2V0IikNCnNlcmllcyA8LSBzdWJzZXQgKGRmX2ZpZWxkcywgaW5kaWNhdG9yPT1pbmQsIHNlbGVjdD0gInNlcmllcyIpDQp1bml0IDwtIHN1YnNldCAoZGZfZmllbGRzLCBpbmRpY2F0b3I9PWluZCwgc2VsZWN0PSAidW5pdCIpDQoNCmxhYl90aXRsZSA8LSBwYXN0ZSAoIlRvcCIsIG4sICAiY291bnRyaWVzIHdpdGggd29yc3QgbGV2ZWxzIG9mIiwgc3ViamVjdCkNCmxhYl94ID0gcGFzdGUgKHNlcmllcywgdW5pdCkNCiAgDQojIFBsb3QgDQpkZiAlPiUNCnNsaWNlX21heCghIWluZGljYXRvciwgbiA9IG4pJT4lDQpnZ3Bsb3QgKGFlcyAoeD0gISFpbmRpY2F0b3IsIHk9IHJlb3JkZXIoY291bnRyeV9uYW1lLCAhIWluZGljYXRvciwgbWF4KSwgZmlsbD1jb250aW5lbnQpKSsgDQogIGdlb21fdGV4dChhZXMobGFiZWw9cm91bmQoISFpbmRpY2F0b3IsMiksIGhqdXN0PS0wLjMpLHNpemU9NSkrDQogIHNjYWxlX2ZpbGxfbWFudWFsICh2YWx1ZXMgPSBjKCJpbmRpYW5yZWQxIiwgInllbGxvdyIsICJkZWVwcGluazEiLCJjeWFuIiwgIm9yYW5nZSIsICJncmF5IiwgInNlYWdyZWVuMyIpLCBicmVha3MgPSBjKCJBZnJpY2EiLCAiQXNpYSIsICJFdXJvcGUiLCJOb3J0aCBBbWVyaWNhIiwgIk9jZWFuaWEiLCAiU2V2ZW4gU2VhcyIsICJTb3V0aCBBbWVyaWNhIikpKw0KICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpKw0KICBsYWJzICh0aXRsZSA9IGxhYl90aXRsZSwgeD1sYWJfeCwgeSA9ICJDb3VudHJpZXMiLCBjYXB0aW9uID0gIkxhdGVzdCBkYXRhIGJldHdlZW4gdGhlIHllYXJzIDIwMTAgdG8gMjAyMCIpKw0KICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQ0KICANCiAgfQ0KDQp0b3BfY291bnRyaWVzX21heCAoaW5kLCBwb3ZlcnR5LCBxdW8ocG92X3JhdGlvKSwgInBvdl9yYXRpbyIpDQoNCmBgYA0KDQoNCiMgQ29sdW1ucyAtIFRvcCBjb3VudHJpZXMNCg0KYGBge3IgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTE1fQ0KDQojIFRoaXMgZnVuY3Rpb24gZ2VuZXJhdGUgYSBsaXN0IHdpdGggdGhlIHJhbmtpbmcgY291bnRyaWVzIGluIG9uZSBzcGVjaWZpYyBpbmRpY2F0b3IgKG1pbmltdW0pDQp0b3BfY291bnRyaWVzX21pbiA8LSBmdW5jdGlvbihkZl9maWVsZHMsIGRmLCBpbmRpY2F0b3IsIGluZCl7DQogIA0Kbj0zNQ0KDQojIFRleHQgZm9yIGxhYnMgKHgsIHkgYW5kIHRpdGxlKQ0Kc3ViamVjdDwtIHN1YnNldCAoZGZfZmllbGRzLCBpbmRpY2F0b3I9PWluZCwgc2VsZWN0PSAiZGF0YXNldCIpDQpzZXJpZXMgPC0gc3Vic2V0IChkZl9maWVsZHMsIGluZGljYXRvcj09aW5kLCBzZWxlY3Q9ICJzZXJpZXMiKQ0KdW5pdCA8LSBzdWJzZXQgKGRmX2ZpZWxkcywgaW5kaWNhdG9yPT1pbmQsIHNlbGVjdD0gInVuaXQiKQ0KDQpsYWJfdGl0bGUgPC0gcGFzdGUgKCJUb3AiLCBuLCAgImNvdW50cmllcyB3aXRoIHdvcnN0IGxldmVscyBvZiIsIHN1YmplY3QpDQpsYWJfeCA9IHBhc3RlIChzZXJpZXMsIHVuaXQpDQogIA0KIyBQbG90IA0KZGYgJT4lDQpzbGljZV9taW4oISFpbmRpY2F0b3IsIG4gPSBuKSU+JQ0KZ2dwbG90IChhZXMgKHg9ICEhaW5kaWNhdG9yLCB5PSByZW9yZGVyKGNvdW50cnlfbmFtZSwgISFpbmRpY2F0b3IsIG1pbiksIGZpbGw9Y29udGluZW50KSkrIA0KICBnZW9tX3RleHQoYWVzKGxhYmVsPXJvdW5kKCEhaW5kaWNhdG9yLDIpLCBoanVzdD0tMC4zKSxzaXplPTUpKw0KICBzY2FsZV9maWxsX21hbnVhbCAodmFsdWVzID0gYygiaW5kaWFucmVkMSIsICJ5ZWxsb3ciLCAiZGVlcHBpbmsxIiwiY3lhbiIsICJvcmFuZ2UiLCAiZ3JheSIsICJzZWFncmVlbjMiKSwgYnJlYWtzID0gYygiQWZyaWNhIiwgIkFzaWEiLCAiRXVyb3BlIiwiTm9ydGggQW1lcmljYSIsICJPY2VhbmlhIiwgIlNldmVuIFNlYXMiLCAiU291dGggQW1lcmljYSIpKSsNCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSsNCiAgbGFicyAodGl0bGUgPSBsYWJfdGl0bGUsIHg9bGFiX3gsIHkgPSAiQ291bnRyaWVzIiwgY2FwdGlvbiA9ICJMYXRlc3QgZGF0YSBiZXR3ZWVuIHRoZSB5ZWFycyAyMDEwIHRvIDIwMjAiKSsNCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLCBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikNCiAgDQogIH0NCg0KdG9wX2NvdW50cmllc19taW4gKGluZCwgcG92ZXJ0eSwgcXVvKGxlbmRfYm9yKSwgImxlbmRfYm9yIikNCg0KYGBgDQoNCiMgQm94cGxvdA0KDQpgYGB7ciBmaWcuaGVpZ2h0PTEwfQ0KIyBUaGlzIGZ1bmN0aW9uIGdlbmVyYXRlcyBhIGJveHBsb3Qgb2YgdGhlIGluZGljYXRvciBmb3IgZWFjaCBjb250aW5lbnQgDQpib3hfcGxvdCA8LSBmdW5jdGlvbihkZl9maWVsZHMsIGRmLCBpbmRpY2F0b3IsIGluZCl7DQogIA0KIyBUZXh0IGZvciBsYWJzICh4LCB5IGFuZCB0aXRsZSkNCnN1YmplY3Q8LSBzdWJzZXQgKGRmX2ZpZWxkcywgaW5kaWNhdG9yPT1pbmQsIHNlbGVjdD0gImRhdGFzZXQiKQ0Kc2VyaWVzIDwtIHN1YnNldCAoZGZfZmllbGRzLCBpbmRpY2F0b3I9PWluZCwgc2VsZWN0PSAic2VyaWVzIikNCnVuaXQgPC0gc3Vic2V0IChkZl9maWVsZHMsIGluZGljYXRvcj09aW5kLCBzZWxlY3Q9ICJ1bml0IikNCg0KbGFiX3RpdGxlIDwtIHBhc3RlICgiQm94cGxvdCAtICIsIHNlcmllcywgImJ5IGNvbnRpbmVudCIsIHVuaXQpDQpsYWJfeSA9IHBhc3RlIChzZXJpZXMsIHVuaXQpDQoNCmRmICU+JQ0KZHJvcF9uYSAoISFpbmRpY2F0b3IpJT4lDQpnZ3Bsb3QgKGFlcyh4PWNvbnRpbmVudCwgeT0gISFpbmRpY2F0b3IsIGZpbGwgPSBjb250aW5lbnQsIGxhYmVsID0gY291bnRyeV9uYW1lKSxzaXplID0gcG9wKSsNCiAgZ2VvbV9ib3hwbG90IChhbHBoYSA9IDAuNikrDQogICNnZW9tX3Zpb2xpbigpKw0KICBnZW9tX3BvaW50KGFscGhhID0gMC42KSsNCiAgbGFicyAodGl0bGUgPSBsYWJfdGl0bGUsIHk9bGFiX3kpKw0KICAjZ2VvbV90ZXh0KGhqdXN0ID0gLS4xLCBudWRnZV94PTAuMDIsIGFscGhhID0gLjQpKw0KICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCkpDQoNCn0NCg0KYm94X3Bsb3QgKGluZCwgZGZfZmlsbCwgcXVvKHBvdl9yYXRpbyksICJwb3ZfcmF0aW8iKQ0KYGBgDQoNCiMgSGlzdG9yaWMgcGVyIGNvdW50cnkgYW5kIHllYXINCg0KYGBge3IgZmlnLmhlaWdodD01MCwgZmlnLndpZHRoPTIyfQ0KDQojIFRoaXMgZnVuY3Rpb24gZ2VuZXJhdGVzIGEgZ3JhcGggd2l0aCB0aGUgaGlzdG9yeSBvZiBlYWNoIHZhcmlhYmxlIGZvciBlYWNoIGNvdW50cnkgDQpwbG90X2hpc3RfY291bnRyaWVzIDwtIGZ1bmN0aW9uIChkZl9maWVsZHMsIGRmLCBpbmRpY2F0b3IsIGluZCwgb3JpZW50YXRpb24pew0KDQojIFRleHQgZm9yIGxhYnMgKHgsIHkgYW5kIHRpdGxlKQ0Kc2VyaWVzIDwtIHN1YnNldCAoZGZfZmllbGRzLCBpbmRpY2F0b3I9PWluZCwgc2VsZWN0PSAic2VyaWVzIikNCnVuaXQgPC0gc3Vic2V0IChkZl9maWVsZHMsIGluZGljYXRvcj09aW5kLCBzZWxlY3Q9ICJ1bml0IikNCg0KbGFiX3RpdGxlIDwtIHBhc3RlIChzZXJpZXMsICJwZXIgY291bnRyeSBhbG9uZyB0aGUgeWVhcnMiLCB1bml0KQ0KDQoNCmRmJT4lDQpkcm9wX25hICghIWluZGljYXRvcikgJT4lDQpnZ3Bsb3QgKGFlcyAoeD0geWVhciwgeT0gcmVvcmRlcihjb3VudHJ5X25hbWUsICEhaW5kaWNhdG9yLCBtYXgpLCBjb2xvcj0gISFpbmRpY2F0b3IsIHNpemU9ISFpbmRpY2F0b3IpKSsNCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jIChkaXJlY3Rpb249IG9yaWVudGF0aW9uKSsNCiAgZ2VvbV9wb2ludCgpKw0KICBzY2FsZV94X2NvbnRpbnVvdXMgKGJyZWFrcyA9IHNlcSgxOTcwLCAyMDIwLCBieSA9IDEwKSkrDQogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDI1KSkrDQogIGxhYnMgKHRpdGxlID0gbGFiX3RpdGxlLCB4PSJZZWFycyIsIHkgPSAiY291bnRyaWVzIikrDQogIGZhY2V0X3dyYXAgKCdjb250aW5lbnQnLCBzY2FsZXMgPSAnZnJlZScpDQoNCn0NCnBsb3RfaGlzdF9jb3VudHJpZXMgKGluZCwgZGZfaGlzdCwgcXVvKHBvdl9yYXRpbyksICJwb3ZfcmF0aW8iLCAtMSkNCg0KYGBgDQoNCiMgSG90IG1hcHMNCg0KYGBge3J9DQojIFRoaXMgZnVuY3Rpb24gZ2VuZXJhdGVzIGEgaG90IG1hcCBvZiB0aGUgaW5kaWNhdG9yIGJ5IGNvbnRpbmVudCANCg0KaG90X21hcCA8LSBmdW5jdGlvbiAoZGZfZmllbGRzLCBkZiwgaW5kaWNhdG9yLCBpbmQsIG9yaWVudGF0aW9uKXsNCiAgDQojIFRleHQgZm9yIGxhYnMgKHRpdGxlKQ0Kc3ViamVjdDwtIHN1YnNldCAoZGZfZmllbGRzLCBpbmRpY2F0b3I9PWluZCwgc2VsZWN0PSAiZGF0YXNldCIpDQpzZXJpZXMgPC0gc3Vic2V0IChkZl9maWVsZHMsIGluZGljYXRvcj09aW5kLCBzZWxlY3Q9ICJzZXJpZXMiKQ0KdW5pdCA8LSBzdWJzZXQgKGRmX2ZpZWxkcywgaW5kaWNhdG9yPT1pbmQsIHNlbGVjdD0gInVuaXQiKQ0KbGFiX3RpdGxlIDwtIHBhc3RlICgiSG90IG1hcCAtICIsIHNlcmllcywgdW5pdCkNCg0KIyBMaW1pdHMgZm9yIHRoZSBsZWdlbmQNCmlmIChvcmllbnRhdGlvbiA9PS0xKXsgDQogICAgZGYxPC0gZGYlPiUNCiAgICBkcm9wX25hICghIWluZGljYXRvciklPiUNCiAgICBncm91cF9ieSAoZ3JvdXAgPSAgZmFjdG9yKG50aWxlKCEhaW5kaWNhdG9yLCA1KSkpICU+JQ0KICAgIHN1bW1hcmlzZSAodXBwZXIgPSBtYXgoISFpbmRpY2F0b3IpLCBsb3dlciA9IG1pbighIWluZGljYXRvcikpICU+JQ0KICAgIG11dGF0ZShsYWJlbCA9IHN0cl9jKHNwcmludGYoIiUuMWYiLCBsb3dlciksICIgdG8gIiwgc3ByaW50ZigiJS4xZiIsIHVwcGVyKSkpDQogICAgICB9DQogIGVsc2V7DQogICAgZGYxPC0gZGYlPiUNCiAgICBkcm9wX25hICghIWluZGljYXRvciklPiUNCiAgICBncm91cF9ieSAoZ3JvdXAgPSAgZmFjdG9yKG50aWxlKGRlc2MoISFpbmRpY2F0b3IpLCA1KSkpICU+JQ0KICAgIHN1bW1hcmlzZSAodXBwZXIgPSBtYXgoISFpbmRpY2F0b3IpLCBsb3dlciA9IG1pbighIWluZGljYXRvcikpICU+JQ0KICAgIG11dGF0ZSAobGFiZWwgPSBzdHJfYyhzcHJpbnRmKCIlLjFmIiwgbG93ZXIpLCAiIHRvICIsIHNwcmludGYoIiUuMWYiLCB1cHBlcikpKQ0KICB9DQojIHByaW50KGRmMSkNCg0KZGYlPiUNCmRyb3BfbmEgKCEhaW5kaWNhdG9yKSAlPiUNCg0KZ2dwbG90IChhZXMgKHg9IHllYXIsIHk9IGNvbnRpbmVudCwgZmlsbCA9IChudGlsZSghIWluZGljYXRvciwgNSkpKSkrIA0KICBnZW9tX3RpbGUoKSsNCiAgc2NhbGVfZmlsbF92aXJpZGlzIChuYW1lID0gcGFzdGUgKHN1YmplY3QsICIoNSBudGlsZSkiKSwgZGlyZWN0aW9uID0gb3JpZW50YXRpb24sIGxhYmVscyA9IGMgKGRmMSRsYWJlbCkpKw0KICBzY2FsZV94X2Rpc2NyZXRlIChicmVha3MgPSBzZXEgKDE5NTAsIDIwMjAsIGJ5PTUpKSsNCiAgbGFicyAodGl0bGUgPSBsYWJfdGl0bGUsIHkgPSAiQ29udGluZW50IiwgeD0gIlllYXIiLCBjYXB0aW9uID0gIkxhdGVzdCBkYXRhIGJldHdlZW4gdGhlIHllYXJzIDIwMTAgdG8gMjAyMCIpDQogICN0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSkpDQp9DQoNCmhvdF9tYXAgKGluZCwgZGZfY29udCwgcXVvKGVtcF92dWxuKSwgImVtcF92dWxuIiwgLTEpDQpgYGANCg0KDQoNCiMgQ29ycmVsYXRpb24NCg0KYGBge3IgZmlnLndpZHRoPTEyfQ0KIyBUaGlzIGZ1bmN0aW9uIGdlbmVyYXRlcyBhIGdyYXBoIHdpdGggdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gMiB2YXJpYWJsZXMgDQpjb3JyZWxhdGlvbiA8LSBmdW5jdGlvbiAoZGZfZmllbGRzLCBkZiwgaW5kaWNhdG9yMSwgaW5kaWNhdG9yMiwgaW5kMSwgaW5kMil7DQogIA0KICANCiMgVGV4dCBmb3IgdGl0bGUNCnNlcmllczEgPC0gc3Vic2V0IChkZl9maWVsZHMsIGluZGljYXRvcj09aW5kMSwgc2VsZWN0PSAic2VyaWVzIikNCnVuaXQxIDwtIHN1YnNldCAoZGZfZmllbGRzLCBpbmRpY2F0b3I9PWluZDEsIHNlbGVjdD0gInVuaXQiKQ0Kc2VyaWVzMiA8LSBzdWJzZXQgKGRmX2ZpZWxkcywgaW5kaWNhdG9yPT1pbmQyLCBzZWxlY3Q9ICJzZXJpZXMiKQ0KdW5pdDIgPC0gc3Vic2V0IChkZl9maWVsZHMsIGluZGljYXRvcj09aW5kMiwgc2VsZWN0PSAidW5pdCIpDQoNCmxhYl94IDwtIHBhc3RlIChzZXJpZXMxLCB1bml0MSkNCmxhYl95IDwtIHBhc3RlIChzZXJpZXMyLCB1bml0MikNCmxhYl90aXRsZSA8LSBwYXN0ZSAobGFiX3gsICJ4IiwgbGFiX3kpDQogIA0KZGYlPiUNCiAgZHJvcF9uYSAoISFpbmRpY2F0b3IxLCAhIWluZGljYXRvcjIpJT4lDQoNCmdncGxvdCAoYWVzICh4PSAhIWluZGljYXRvcjEsIHk9ICEhaW5kaWNhdG9yMiwgY29sb3IgPSBjb250aW5lbnQsbGFiZWwgPSBjb3VudHJ5X25hbWUsIHNpemUgPSBudGlsZShwb3AsNSkpKSsNCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNikrDQogIHNjYWxlX2NvbG91cl9tYW51YWwgKHZhbHVlcyA9IGMoImluZGlhbnJlZDEiLCAieWVsbG93IiwgImRlZXBwaW5rMSIsImN5YW4iLCAib3JhbmdlIiwgImdyYXkiLCAic2VhZ3JlZW4zIikpKw0KICBsYWJzICh0aXRsZSA9IGxhYl90aXRsZSwgeD1sYWJfeCwgeSA9IGxhYl95LCBjYXB0aW9uID0gIkxhdGVzdCBkYXRhIGJldHdlZW4gdGhlIHllYXJzIDIwMTAgdG8gMjAyMCIpKw0KICBnZW9tX3RleHQoaGp1c3QgPSAtLjEsIG51ZGdlX3g9MC4wMiwgYWxwaGEgPSAuMykNCg0KfQ0KDQpjb3JyZWxhdGlvbiAoaW5kLCBkZl9maWxsLCBxdW8oaW5lcV8xMCksIHF1byhwb3ZfcmF0aW8pLCAiaW5lcV8xMCIsICJwb3ZfcmF0aW8iKQ0KYGBgDQoNCk90aGVyIGdyYXBoaWNzLCBtb3JlIHNwZWNpZmljIGFuZCBjb21wbGV4LCB3ZXJlIGluY2x1ZGVkIGF0IHRoZSBlbmQgb2YgdGhlIHJlcG9ydC4NCg0KDQojIFJFUE9SVA0KDQoNCiMjICoqIE9WRVJWSUVXIE9GIFBPVkVSVFksIEVEVUNBVElPTiBBTkQgRU1QTE9ZTUVOVCBJTiBUSEUgV09STEQqKg0KDQoNCioqUE9WRVJUWSoqDQoNCioqV2hlcmUgZG8gdGhlIHdvcmxk4oCZcyBwb29yZXN0IHBlb3BsZSBsaXZlIHRvZGF5PyoqDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0V9DQptYXBfaW5kaWNhdG9yIChpbmQsIGRmX2ZpbGwsIHF1byhwb3ZfcmF0aW8pLCAicG92X3JhdGlvIiwgLTEpDQpgYGANCg0KQXBwcm94aW1hdGVseSAxLzUgb2YgdGhlIGNvdW50cmllcyBpbiB0aGUgd29ybGQgaGF2ZSBtb3JlIHRoYW4gMjYlIG9mIHRoZSBwb3B1bGF0aW9uIGxpdmluZyB3aXRoIHVwIHRvIDEuOTAgYSBkYXkuIFRoZXNlIGNvdW50cmllcyBhcmUgY29uY2VudHJhdGVkIGluIEFmcmljYS4NCg0KYGBge3IgbWVzc2FnZT1GQUxTRX0NCm1hcF9pbmRpY2F0b3JfY29udGluZW50ICgiQWZyaWNhIiwgaW5kLCBkZl9maWxsLCBxdW8ocG92X3JhdGlvKSwgInBvdl9yYXRpbyIsIC0xKQ0KYGBgDQoNCkFuYWx5emluZyBBZnJpY2EgaW4gbW9yZSBkZXRhaWwsIGl0IGlzIHBvc3NpYmxlIHRvIHNlZSAgdGhlIGxhcmdlc3QgcmVnaW9uIG9mIHBvdmVydHksIHdoZXJlIDUxIHRvIDc3JSBvZiBwb3B1bGF0aW9uIGlzIGxpdmluZyB3aXRoIHVwIHRvIDEuOTAgYSBkYXkuDQoNCg0KKipVbmRlciB3aGF0IGNvbmRpdGlvbnMgcGVvcGxlIGxpdmUgdG9kYXk/KioNCg0KYGBge3IgbWVzc2FnZT1GQUxTRX0NCm1hcF9pbmRpY2F0b3IgKGluZCwgZGZfZmlsbCwgcXVvIChwb3Bfc2x1bSksInBvcF9zbHVtIiwgLTEpDQptYXBfaW5kaWNhdG9yIChpbmQsIGRmX2ZpbGwsIHF1byAoYWNjX2VsZSksImFjY19lbGUiLCAxKQ0KbWFwX2luZGljYXRvcl9jb250aW5lbnQgKCJBZnJpY2EiLCBpbmQsIGRmX2ZpbGwsIHF1byhhY2NfZWxlKSwgImFjY19lbGUiLCAxKSAjIFpvb20gaW4gQWZyaWNhLCBidXQgdGhlcmUgYXJlIG90aGVyIGNvbnRpbmVudHMgd2l0aCBsb3cgdmFsdWVzDQptYXBfaW5kaWNhdG9yIChpbmQsIGRmX2ZpbGwsIHF1byAoYWNjX3dhdCksImFjY193YXQiLCAxKQ0KbWFwX2luZGljYXRvciAoaW5kLCBkZl9maWxsLCBxdW8gKGFjY19zYW4pLCJhY2Nfc2FuIiwgLTEpDQptYXBfaW5kaWNhdG9yX2NvbnRpbmVudCAoIkFmcmljYSIsIGluZCwgZGZfZmlsbCwgcXVvKGFjY19zYW4pLCAiYWNjX3NhbiIsIC0xKSAjIFpvb20gaW4gQWZyaWNhLCBidXQgdGhlcmUgYXJlIG90aGVyIGNvbnRpbmVudHMgd2l0aCBsb3cgdmFsdWVzDQptYXBfaW5kaWNhdG9yIChpbmQsIGRmX2ZpbGwsIHF1byAoY2hpbGRfbW9ydCksImNoaWxkX21vcnQiLCAtMSkNCg0KYGBgDQoNClRoZXJlIGFyZSBzdGlsbCBtYW55IGNvdW50cmllcyB3aXRoIGEgaGlnaCBwZXJjZW50YWdlIG9mIHRoZSBwb3B1bGF0aW9uIGxpdmluZyBpbiBzdWJodW1hbiBjb25kaXRpb25zOg0KDQotIEFwcHJveGltYXRlbHkgMy81IG9mIHRoZSBjb3VudHJpZXMgaGF2ZSBtb3JlIHRoYW4gMjclIG9mIHVyYmFuIHBvcHVsYXRpb24gbGl2aW5nIGluIHNsdW1zOyAxLzUgb2YgdGhlIGNvdW50cmllcyBoYXZlIGZyb20gNTglIHVwIHRvIDk1JSBvZiB1cmJhbiBwb3B1bGF0aW9uIGxpdmluZyBpbiBzbHVtczsNCi0gVGhlcmUgYXJlIGNvdW50cmllcyB3aXRoIG9ubHkgMTElIHRvIDMwJSBvZiB0aGUgcG9wdWxhdGlvbiB3aXRoIGFjY2VzcyB0byBlbGVjdHJpY2l0eTsNCi0gMS81IG9mIHRoZSBjb3VudHJpZXMgaW4gdGhlIHdvcmxkIGhhdmUgYSBsb3cgcGVyY2VudGFnZSBvZiB0aGUgcG9wdWxhdGlvbiB3aXRoIGFjY2VzcyB0byBiYXNpYyBkcmlua2luZyB3YXRlciBzZXJ2aWNlcyAoMzglIHRvIDc4JSBvZiB0aGUgcG9wdWxhdGlvbik7DQotIEFuZCBjb3VudHJpZXMgd2l0aCA0MCUgdG8gNjglIG9mIHRoZSBwb3B1bGF0aW9uIHByYWN0aWNpbmcgb3BlbiBkZWZlY2F0aW9uOw0KLSBJbiBBZnJpY2EgYW5kIHNvbWUgY291bnRyaWVzIG9mIEFzaWEgdGhlcmUgaXMgYSBoaWdoIGluZmFudCBtb3J0YWxpdHkgcmF0ZSAoMzYgdG8gODEgcGVyIDEsMDAwIGxpdmUgYmlydGhzKS4NCg0KDQoqKldoZXJlIGRvIHRoZSB3b3JsZOKAmXMgcG9vcmVzdCBwZW9wbGUgbGl2ZSB0b2RheT8qKg0KDQpgYGB7cn0NCmhpc3RvZ3JhbSAoaW5kLCBwb3ZlcnR5LCBwb3ZlcnR5JHBvdl9yYXRpbywgInBvdl9yYXRpbyIpKw0KZ2VvbV90ZXh0KHggPSA0MCwgeSA9IDUwLCBsYWJlbCA9ICIxMCBjb3VudHJpZXMgd2l0aCBtb3JlIHRoYW4gNTAlIG9mIHRoZSBwb3B1bGF0aW9uDQogICAgICAgICAgbGl2aW5nIGluIGNvbmRpdGlvbnMgb2YgZXh0cmVtZSBwb3ZlcnR5IiwgaGp1c3QgPSAwLCB2anVzdCA9IDAuNSwgY29sb3VyID0gInJlZCIsIHNpemUgPSA0KSsNCmdlb21fc2VnbWVudChhZXMoeCA9IDU1LCB5ID0gNDAsIHhlbmQgPSA1NSwgeWVuZCA9IDE1KSwgY29sb3VyPSJyZWQiLCBzaXplPTAuNSwgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuNSwgImNtIikpKSsNCg0KZ2VvbV90ZXh0KHggPSAyMCwgeSA9IDcwLCBsYWJlbCA9ICIzNSBjb3VudHJpZXMgd2l0aCBtb3JlIHRoYW4gMjAlIG9mIHRoZSBwb3B1bGF0aW9uDQogICAgICAgICAgbGl2aW5nIGluIGNvbmRpdGlvbnMgb2YgZXh0cmVtZSBwb3ZlcnR5IiwgaGp1c3QgPSAwLCB2anVzdCA9IDAuNSwgY29sb3VyID0gInJlZCIsIHNpemUgPSA0KSsNCmdlb21fc2VnbWVudChhZXMoeCA9IDI1LCB5ID0gNjAsIHhlbmQgPSAyNSwgeWVuZCA9IDE1KSwgY29sb3VyPSJyZWQiLCBzaXplPTAuNSwgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuNSwgImNtIikpKQ0KDQpgYGANCg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTV9DQp0b3BfY291bnRyaWVzX21heCAoaW5kLCBwb3ZlcnR5LCBxdW8ocG92X3JhdGlvKSwicG92X3JhdGlvIikNCg0KYGBgDQoNClRoZSB0b3AgMzAgY291bnRyaWVzIHdpdGggZXh0cmVtZWx5IHBvdmVydHkgYXJlIGZyb20gQWZyaWNhLg0KDQoNCioqSG93IGlzIHRoZSBiZWhhdmlvdXIgb2YgZXh0cmVtZSBwb3ZlcnR5IGJ5IGNvbnRpbmVudD8qKg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTEwfQ0KYm94X3Bsb3QgKGluZCwgZGZfZmlsbCwgcXVvKHBvdl9yYXRpbyksICJwb3ZfcmF0aW8iKQ0KIyBib3hfcGxvdCAoaW5kLCBkZl9maWxsLCBxdW8oYWNjX2VsZSksICJhY2NfZWxlIikNCmBgYA0KSW4gYWRkaXRpb24gdG8gQWZyaWNhLCBBc2lhLCBOb3J0aCBBbWVyaWNhIGFuZCBPY2VhbmlhIGhhdmUgY291bnRyaWVzIHdpdGggbW9yZSB0aGFuIDIwJSBvZiB0aGUgcG9wdWxhdGlvbiBsaXZpbmcgaW4gcG92ZXJ0eS4gDQoNCg0KKipIb3cgaGFzIGV2b2x2ZWQgcG92ZXJ0eSBwZXIgY291bnRyeSBhbG9uZyB0aGUgeWVhcnM/KioNCg0KYGBgYGBge3IgZmlnLmhlaWdodD01MCwgZmlnLndpZHRoPTIyfQ0KcGxvdF9oaXN0X2NvdW50cmllcyAoaW5kLCBkZl9oaXN0LCBxdW8ocG92X3JhdGlvKSwgInBvdl9yYXRpbyIsIC0xKQ0KYGBgDQoNClRoZSBleHRyZW1lbHkgcG92ZXJ0eSBpcyBkZWNyZWFzaW5nIGluIHRoZSBtYWpvcml0eSBvZiBjb3VudHJpZXMgaW4gdGhlIHdvcmxkLg0KDQpBc2lhOiBjb25zaWRlcmFibGUgcmVkdWN0aW9uIGluIGV4dHJlbWUgcG92ZXJ0eSwgZS5nLixJbmRvbmVzaWEsIENoaW5hLCBOZXBhbCBhbmQgSW5kaWEuIE9ubHkgb25lIGV4Y2VwdGlvbjogVXpiZWtpc3RhbiwgYnV0IHRoZXJlIGlzIG5vIGRhdGEgZnJvbSByZWNlbnQgeWVhcnMgb2YgdGhpcyBjb3VudHJ5LiANCkFtZXJpY2FzOiBhbHNvIGhhZCBhIHJlZHVjdGlvbiwgd2l0aCBleGNlcHRpb24gb2YgVmVuZXp1ZWxhICh0aGF0IGRvZXNuJ3QgaGF2ZSBkYXRhIGZvciB0aGUgcmVjZW50IHllYXJzKS4gDQpPY2VhbmlhIGFuZCBFdXJvcGU6IHZhbHVlcyBoYXZlIGRlY3JlYXNlZCBvciByZW1haW4gcmVsYXRpdmVseSBsb3cgb3ZlciB0aGUgeWVhcnMuDQpJbiBBZnJpY2EsIHRoZXJlIGFyZSBtb3JlIGV4dHJlbWUgcG92ZXJ0eSBhbmQgYWx0aG91Z2ggaXQgaXMgZGVjcmVhc2luZyBpbiBtYW55IGNvdW50cmllcywgaW4gc29tZSBvdGhlcnMgaXQgaXMgaW5jcmVhc2luZyAoTWFkYWdhc2NhciwgTWFsYXdpLCBHdWluZWEgQmlzc2F1LCBBbmdvbGEsIFNhbyBUb21lIGFuZCBQcmluY2lwZSwgWmFtYmlhLCBaaW1iYWJ3ZSBhbmQgQ290ZSBkJ0l2b2lyZSkuDQoNCg0KKipIb3cgaGFzIGV2b2x2ZWQgdGhlIHBvdmVydHkgYnkgY29udGluZW50IGFsb25nIHRoZSB5ZWFycz8qKg0KDQpgYGB7cn0NCmhvdF9tYXAgKGluZCwgZGZfY29udCwgcXVvKHBvdl9yYXRpbyksICJwb3ZfcmF0aW8iLCAtMSkNCmBgYA0KDQpUaGUgZ3JhcGggYWJvdmUgc2hvd3MgdGhlIGltcHJvdmVtZW50IGluIHBlcmZvcm1hbmNlIG9uIHRoaXMgaW5kaWNhdG9yIGluIGFsbCBjb250aW5lbnRzLiANCk9ubHkgaW4gTWlkZGxlIEVhc3QgJiBOb3J0aCBBZnJpY2EgdGhpcyBpbmRpY2F0b3Igd29yc2VuZWQgaW4gcmVjZW50IHllYXJzLg0KDQoNCioqRURVQ0FUSU9OKioNCg0KDQoNCiIqKkluIHdoaWNoIGNvdW50cmllcyBhcmUgbW9yZSBjaGlsZHJlbiBvdXQgb2Ygc2Nob29sPyoqDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0V9DQptYXBfaW5kaWNhdG9yIChpbmQsIGRmX2ZpbGwsIHF1byhvdXRfc2NoX2NoaWxkKSwib3V0X3NjaF9jaGlsZCIsIC0xKQ0KYGBgDQpBcHByb3hpbWF0ZWx5IDEvNSBvZiB0aGUgY291bnRyaWVzIGhhdmUgbW9yZSB0aGFuIDEyJSBvZiB0aGUgY2hpbGRyZW4gb3V0IG9mIHNjaG9vbC4gDQoNCg0KYGBge3J9DQpoaXN0b2dyYW0gKGluZCwgZWR1Y2F0aW9uLCBlZHVjYXRpb24kb3V0X3NjaF9jaGlsZCwgIm91dF9zY2hfY2hpbGQiKSsNCmdlb21fdGV4dCh4ID0gNDAsIHkgPSA1MCwgbGFiZWwgPSAiMiBjb3VudHJpZXMgd2l0aCBtb3JlIHRoYW4gNTAlIG9mIHRoZSBjaGlsZHJlbiANCiAgICAgICAgICBvdXQgb2Ygc2Nob29sICglIG9mIHByaW1hcnkgc2Nob29sIGFnZSkiLCBoanVzdCA9IDAsIHZqdXN0ID0gMC41LCBjb2xvdXIgPSAicmVkIiwgc2l6ZSA9IDQpKw0KZ2VvbV9zZWdtZW50KGFlcyh4ID0gNTUsIHkgPSA0MCwgeGVuZCA9IDU1LCB5ZW5kID0gMTUpLCBjb2xvdXI9InJlZCIsIHNpemU9MC41LCBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC41LCAiY20iKSkpKw0KDQpnZW9tX3RleHQoeCA9IDIwLCB5ID0gNzAsIGxhYmVsID0gIjIxIGNvdW50cmllcyB3aXRoIG1vcmUgdGhhbiAyMCUgb2YgdGhlIGNoaWxkcmVuIG91dCBvZiBzY2hvb2wgDQogICAgICAgICAgKCUgb2YgcHJpbWFyeSBzY2hvb2wgYWdlKSIsIGhqdXN0ID0gMCwgdmp1c3QgPSAwLjUsIGNvbG91ciA9ICJyZWQiLCBzaXplID0gNCkrDQpnZW9tX3NlZ21lbnQoYWVzKHggPSAyNSwgeSA9IDYwLCB4ZW5kID0gMjUsIHllbmQgPSAxNSksIGNvbG91cj0icmVkIiwgc2l6ZT0wLjUsIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgwLjUsICJjbSIpKSkNCg0KYGBgDQoNCmBgYHtyIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xNX0NCnRvcF9jb3VudHJpZXNfbWF4IChpbmQsIGVkdWNhdGlvbiwgcXVvKG91dF9zY2hfY2hpbGQpLCJvdXRfc2NoX2NoaWxkIikNCg0KYGBgDQpTb3V0aCBTdWRhbiBpcyB0aGUgd29yc3QgY291bnRyeSBpbiB0aGlzIGluZGljYXRvciwgd2l0aCA2Mi4zJSBvZiBjaGlsZHJlbiBvdXQgb2Ygc2Nob29sICglIG9mIHByaW1hcnkgc2Nob29sIGFnZSkuDQpJbiBOb3J0aCBBbWVyaWNhLCBUdXJrcyBhbmQgQ2FpY29zIElzbGFuZHMgaXMgdGhlIHdvcnN0IGNvdW50cnkgaW4gcHJpbWFyeSBlZHVjYXRpb24sIHdpdGggMjcuODQlIG9mIGNoaWxkcmVuIG91dCBvZiBzY2hvb2wuDQpTeXJpYW4gQXJhYiBSZXB1YmxpYyBpbiBBc2lhLCB3aXRoIDI3LjYxJSBvZiBjaGlsZHJlbiBvdXQgb2Ygc2Nob29sLg0KTWFyc2hhbGwgSXNsYW5kcyBpbiBPY2VhbmlhLCB3aXRoIDI1Ljg2JSBvZiBjaGlsZHJlbiBvdXQgb2Ygc2Nob29sLg0KQnVsZ2FyaWEgYXBwZWFycyBpbiB0aGUgMzV0aCBwb3NpdGlvbiBpbiB0aGUgcmFua2luZyBvZiBjb3VudHJpZXMgd2l0aCB0aGUgbW9zdCBjaGlsZHJlbiBvdXQgb2Ygc2Nob29sLg0KDQoNCioqSG93IGFyZSB0aGUgZWR1Y2F0aW9uIGluZGljYXRvciBzdGF0aXN0aWNzIGJ5IGNvbnRpbmVudCAoYm94cGxvdCk/KiogDQoNCmBgYHtyIGZpZy5oZWlnaHQ9MTB9DQpib3hfcGxvdCAoaW5kLCBkZl9maWxsLCBxdW8ob3V0X3NjaF9jaGlsZCksIm91dF9zY2hfY2hpbGQiKQ0KYGBgDQoNCioqSG93IGhhcyBldm9sdmVkIHRoZSBlZHVjYXRpb24gaW5kaWNhdG9yIHBlciBjb3VudHJ5IGFsb25nIHRoZSB5ZWFycz8qKg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTUwLCBmaWcud2lkdGg9MjJ9DQpwbG90X2hpc3RfY291bnRyaWVzIChpbmQsIGRmX2hpc3QsIHF1byhvdXRfc2NoX2NoaWxkKSwgIm91dF9zY2hfY2hpbGQiLCAtMSkNCmBgYA0KVGhlIHZhc3QgbWFqb3JpdHkgb2YgY291bnRyaWVzIGluIHRoZSB3b3JsZCBhcmUgaW1wcm92aW5nIHRoZWlyIHBlcmZvcm1hbmNlIGluIHRoaXMgaW5kaWNhdG9yLiANCkhvd2V2ZXIsIHRoZXJlIGFyZSBzdGlsbCBzb21lIGNvdW50cmllcyB0aGF0IGFyZSBnZXR0aW5nIHdvcnNlLCBzdWNoIGFzIFNvdXRoIFN1ZGFuLCBFcXVhdG9yaWFsIEd1aW5lYSwgQ29uZ28gKERlbS4gUmVwLiksIFR1cmNzIGFuZCBDYWljb3MgSXNsYW5kcywgU3VyaW5hbWUsIEJvbGl2aWEuIFBhcmFndWF5IGFuZCBWZW5lenVlbGEgYWxyZWFkeSBpbXByb3ZlZCBhbmQgZ290IHdvcnNlLg0KDQoNCioqSG93IGhhcyBldm9sdmVkIHRoZSBlZHVjYXRpb24gaW5kaWNhdG9yIGJ5IGNvbnRpbmVudCBhbG9uZyB0aGUgeWVhcnM/KioNCg0KYGBge3J9DQpob3RfbWFwIChpbmQsIGRmX2NvbnQsIHF1byhvdXRfc2NoX2NoaWxkKSwgIm91dF9zY2hfY2hpbGQiLCAtMSkNCmBgYA0KDQpUaGUgZ3JhcGggYWJvdmUgc2hvd3MgdGhlIGltcHJvdmVtZW50IGluIHBlcmZvcm1hbmNlIG9uIHRoaXMgaW5kaWNhdG9yIGluIGFsbCBjb250aW5lbnRzLg0KDQoNCioqRU1QTE9ZTUVOVCoqDQoNCg0KKipJbiB3aGljaCBjb3VudHJpZXMgYXJlIG1vcmUgdW5lbXBsb3ltZW50IGFuZCB2dWxuZXJhYmxlIGVtcGxveW1lbnQ/KioNCg0KYGBge3IgbWVzc2FnZT1GQUxTRX0NCm1hcF9pbmRpY2F0b3IgKGluZCwgZGZfZmlsbCwgcXVvKHVuZW1wKSwidW5lbXAiLCAtMSkNCm1hcF9pbmRpY2F0b3IgKGluZCwgZGZfZmlsbCwgcXVvIChlbXBfdnVsbiksImVtcF92dWxuIiwgLTEpDQoNCmBgYA0KQXBwcm94aW1hdGVseSAxLzUgb2YgdGhlIGNvdW50cmllcyBoYXZlIG1vcmUgdGhhbiAxMSUgb2YgdW5lbXBsb3ltZW50IChwZXJzb25zIHVuZW1wbG95ZWQvIHRvdGFsIGxhYm9yIGZvcmNlKS4NCkFwcHJveGltYXRlbHkgMi81IG9mIHRoZSBjb3VudHJpZXMgaGF2ZSBtb3JlIHRoYW4gNDAlIG9mIHZ1bG5lcmFibGUgZW1wbG95bWVudCAoJSBvZiB0b3RhbCBlbXBsb3ltZW50KS4NCg0KDQpgYGB7cn0NCmhpc3RvZ3JhbSAoaW5kLCB1bmVtcGxveW1lbnQsIHVuZW1wbG95bWVudCR1bmVtcCwgInVuZW1wIikrDQpnZW9tX3RleHQoeCA9IDIwLCB5ID0gNzAsIGxhYmVsID0gIjcgY291bnRyaWVzIHdpdGggbW9yZSB0aGFuIDIwJSBvZiB0aGUgbGFib3VyIGZvcmNlIHVuZW1wbG95ZWQpIiwgaGp1c3QgPSAwLCB2anVzdCA9IDAuNSwgDQogICAgICAgICAgY29sb3VyID0gInJlZCIsIHNpemUgPSA0KSsNCmdlb21fc2VnbWVudChhZXMoeCA9IDI1LCB5ID0gNjAsIHhlbmQgPSAyNSwgeWVuZCA9IDE1KSwgY29sb3VyPSJyZWQiLCBzaXplPTAuNSwgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuNSwgImNtIikpKQ0KYGBgDQoNCmBgYHtyfQ0KaGlzdG9ncmFtIChpbmQsIGVtcF92dWxuZXJhYmxlLCBlbXBfdnVsbmVyYWJsZSRlbXBfdnVsbiwgImVtcF92dWxuIikrDQpnZW9tX3RleHQoeCA9IDQwLCB5ID0gNDAsIGxhYmVsID0gIjU5IGNvdW50cmllcyB3aXRoIG1vcmUgdGhhbiA1MCUgb2YgDQogICAgICAgICAgdnVsbmVyYWJsZSBlbXBsb3ltZW50KSIsIGhqdXN0ID0gMCwgdmp1c3QgPSAwLjUsIGNvbG91ciA9ICJyZWQiLCBzaXplID0gNCkrDQpnZW9tX3NlZ21lbnQoYWVzKHggPSA1NSwgeSA9IDM1LCB4ZW5kID0gNTUsIHllbmQgPSAxNSksIGNvbG91cj0icmVkIiwgc2l6ZT0wLjUsIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgwLjUsICJjbSIpKSkrDQoNCmdlb21fdGV4dCh4ID0gMjcsIHkgPSA1MCwgbGFiZWwgPSAiMTE2IGNvdW50cmllcyB3aXRoIG1vcmUgdGhhbiAyMCUgb2YgDQogICAgICAgICAgdnVsbmVyYWJsZSBlbXBsb3ltZW50KSIsIGhqdXN0ID0gMCwgdmp1c3QgPSAwLjUsIGNvbG91ciA9ICJyZWQiLCBzaXplID0gNCkrDQpnZW9tX3NlZ21lbnQoYWVzKHggPSAyNSwgeSA9IDUzLCB4ZW5kID0gMjUsIHllbmQgPSAyNSksIGNvbG91cj0icmVkIiwgc2l6ZT0wLjUsIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgwLjUsICJjbSIpKSkNCmBgYA0KDQoNCmBgYHtyIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xNX0NCnRvcF9jb3VudHJpZXNfbWF4IChpbmQsIHVuZW1wbG95bWVudCwgcXVvKHVuZW1wKSwidW5lbXAiKQ0KdG9wX2NvdW50cmllc19tYXggKGluZCwgZW1wX3Z1bG5lcmFibGUsIHF1byAoZW1wX3Z1bG4pLCJlbXBfdnVsbiIpDQpgYGANCg0KVW5lbXBsb3ltZW50Og0KDQpUaGVyZSBhcmUgY291bnRyaWVzIGZyb20gYWxsIGNvbnRpbmVudHMgaW4gdGhpcyByYW5raW5nLg0KU291dGggQWZyaWNhIGFwcGVhcnMgZmlyc3QgaW4gdGhlIHJhbmtpbmcgd2l0aCAyOCUgdW5lbXBsb3ltZW50Lg0KDQoNClZ1bG5lcmFibGUgZW1wbG95bWVudDoNCg0KVGhlc2UgMzUgY291bnRyaWVzIGhhdmUgbW9yZSB0aGFuIDcxJSBvZiBwZW9wbGUgd29ya2luZyBpbiB2dWxuZXJhYmxlIGVtcGxveW1lbnQuDQpCdXJ1bmRpLCBOaWdlciwgQ2hhZCwgQ2VudHJhbCBBZnJpY2FuIGFuZCBHdWluZWEgYXJlIGNvdW50cmllcyB3aXRoIG1vcmUgcGVyY2VudGFnZSBvZiB2dWxuZXJhYmxlIGVtcGxveW1lbnQgaW4gQWZyaWNhLg0KSW4gQXNpYSwgS29yZWEsIEFmZ2hhbmlzdGFuLCBMYW8gUERSLCBDb25nbyBhbmQgSW5kaWEgaGF2ZSB0aGUgd29yc3QgcGVyZm9ybWFuY2UgaW4gdGhpcyBpbmRpY2F0b3IuDQpBbHNvLCBQYXB1YSBOZXcgR3VpbmVhIGluIE9jZWFuaWEgYW5kIEhhaXRpIGluIE5vcnRoIEFtZXJpY2EgYXJlIGluIHRoZSByYW5raW5nLg0KDQoNCioqSG93IGFyZSB0aGUgdW5lbXBsb3ltZW50IGFuZCB2dWxuZXJhYmxlIGVtcGxveW1lbnQgaW5kaWNhdG9ycyBzdGF0aXN0aWNzIGJ5IGNvbnRpbmVudCAoYm94cGxvdCk/KiogDQoNCmBgYHtyIGZpZy5oZWlnaHQ9MTB9DQpib3hfcGxvdCAoaW5kLCBkZl9maWxsLCBxdW8odW5lbXApLCJ1bmVtcCIpDQpib3hfcGxvdCAoaW5kLCBkZl9maWxsLCBxdW8gKGVtcF92dWxuKSwiZW1wX3Z1bG4iKQ0KDQpgYGANCg0KKipIb3cgaGF2ZSBldm9sdmVkIHVuZW1wbG95bWVudCBhbmQgdnVsbmVyYWJsZSBlbXBsb3ltZW50IHBlciBjb3VudHJ5IGFsb25nIHRoZSB5ZWFycz8qKg0KDQpgYGBgYGB7ciBmaWcuaGVpZ2h0PTUwLCBmaWcud2lkdGg9MjJ9DQpwbG90X2hpc3RfY291bnRyaWVzIChpbmQsIGRmX2hpc3QsIHF1byh1bmVtcCksICJ1bmVtcCIsIC0xKQ0KcGxvdF9oaXN0X2NvdW50cmllcyAoaW5kLCBkZl9oaXN0LCBxdW8oZW1wX3Z1bG4pLCAiZW1wX3Z1bG4iLCAtMSkNCmBgYA0KVGhlcmUgaXMgbm8gb3NjaWxsYXRpb24gcGF0dGVybiBvZiB1bmVtcGxveW1lbnQgYW5kIHZ1bG5lcmFibGUgd29yayBhbW9uZyB0aGUgY291bnRyaWVzLg0KDQpHZW5lcmFsbHksIHRoZSB1bmVtcGxveW1lbnQgbGV2ZWwgZmx1Y3R1YXRlcyBvdmVyIHRoZSB5ZWFycyBpbiBlYWNoIGNvdW50cnkuIA0KQm9zbmlhIGFuZCBOb3J0aCBNYWNlZG9uaWEgaGF2ZSB0aGUgd29yc3QgdW5lbXBsb3ltZW50IHJhdGVzIGluIEV1cm9wZSwgV2VzdCBCYW5rIGFuZCBHYXphIGFuZCBBcm1lbmlhIGluIEFzaWEsIFNvdXRoIEFmcmljYSBhbmQgDQpMZXNvdGhvIGluIEFmcmljYSwgU3RhIEx1Y2lhIGFuZCBTdCBWaW5jZW50IGFuZCB0aGUgR3JlbmFkaW5lcyBpbiBOb3J0aCBBbWVyaWNhLg0KDQpSZWdhcmRpbmcgdGhlIHZ1bG5lcmFibGUgdW5lbXBsb3ltZW50LCBpbiBzb21lIGNvdW50cmllcywgdGhlcmUgaGFzIGJlZW4gbm8gZXZvbHV0aW9uIG9mIHRoaXMgaW5kaWNhdG9yIGFsb25nIHRoZSB5ZWFycywgYWx0aG91Z2ggaW4gdGhlIGdyYXBoaWMgYmVsb3cgd2UgY2FuIG5vdGljZSBhIGRlY3JlYXNlIGluIHRoaXMga2luZCBvZiBlbXBsb3ltZW50Lg0KDQoNCioqSG93IGhhdmUgZXZvbHZlZCB1bmVtcGxveW1lbnQgYW5kIHZ1bG5lcmFibGUgZW1wbG95bWVudCBwZXIgY29udGluZW50IGFsb25nIHRoZSB5ZWFycz8qKg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFfQ0KaG90X21hcCAoaW5kLCBkZl9jb250LCBxdW8odW5lbXApLCAidW5lbXAiLCAtMSkNCmhvdF9tYXAgKGluZCwgZGZfY29udCwgcXVvKGVtcF92dWxuKSwgImVtcF92dWxuIiwgLTEpDQoNCmBgYA0KU2luY2UgdGhlIDE5OTBzLCB0aGUgdW5lbXBsb3ltZW50IHJhdGUgaW4gdGhlIE1pZGRsZSBFYXN0IGFuZCBOb3J0aCBBZnJpY2EgaGFzIGJlZW4gaGlnaCBhbmQgaW4gRWFzdCBBc2lhICYgUGFjaWZpY2EgbG93Lg0KSW4gdGhlIGdyYWhpYyBhYm92ZSwgaXQgaXMgcG9zc2libGUgdG8gaWRlbnRpZnkgdGhlIGNyaXNlcyBvZiAyMDA4IGFuZCAyMDA5IGluIE5vcnRoIEFtZXJpY2EuDQoNCkFuYWx5emluZyB0aGUgdnVsbmVyYWJsZSBlbXBsb3ltZW50IGluIHRoZSB3b3JsZCBhbmQgaW4gdGhlIGNvbnRpbmVudHMsIGluIGdlbmVyYWwsIGl0IGhhcyByZWR1Y2VkLiBFeGNlcHQgaW4gTGF0aW4gQW1lcmljYSAmIENhcmliYmVhbiB3aGVyZSBpdCBpbmNyZWFzZXMgaW4gcmVjZW50IHllYXJzLg0KDQoNCiMgRXh0cmEgQW5hbGlzZXMgLSBMZW5kIGFuZCBCb3Jyb3dpbmcgKGFzIGEgJSBvZiBHRFApDQoNCg0KKipXaGljaCBvZiB0aGUgY291bnRyaWVzIGhhdmUgdGhlIGhpZ2hlc3QgbmV0IGJvcnJvd2luZyAoYXMgYSAlIG9mIEdEUCk/KioNCg0KICANCmBgYHtyfQ0KbWFwX2luZGljYXRvcl9kaXZlcmdpbmcgKGluZCwgZGZfZmlsbCwgcXVvIChsZW5kX2JvciksImxlbmRfYm9yIiwgLTEpDQpgYGANCg0KYGBge3IgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTE1fQ0KdG9wX2NvdW50cmllc19taW4gKGluZCwgZWR1Y2F0aW9uLCBxdW8obGVuZF9ib3IpLCJsZW5kX2JvciIpDQoNCmBgYA0KDQoNCioqVGhlIGhpZ2hlciB0aGUgdW5lbXBsb3ltZW50IHRoZSBoaWdoZXIgdGhlIHBvdmVydHk/KioNCmBgYHtyfQ0KY29ycmVsYXRpb24gKGluZCwgZGZfZmlsbCwgcXVvKHVuZW1wKSwgcXVvKHBvdl9yYXRpbyksICJ1bmVtcCIsICJwb3ZfcmF0aW8iKQ0KYGBgDQoNCg0KDQoqKlRoZSBoaWdoZXIgdGhlIHZ1bG5lcmFibGUgZW1wbG95bWVudCB0aGUgaGlnaGVyIHRoZSBwb3ZlcnR5PyoqDQpgYGB7cn0NCmNvcnJlbGF0aW9uIChpbmQsIGRmX2ZpbGwsIHF1byhlbXBfdnVsbiksIHF1byhwb3ZfcmF0aW8pLCAiZW1wX3Z1bG4iLCAicG92X3JhdGlvIikNCmBgYA0KDQpUaGVzZSB2YXJpYWJsZXMgaGF2ZSBhIGdvb2QgY29ycmVsYXRpb24uDQoNCg0KKipUaGUgbG93ZXIgdGhlIGVkdWNhdGlvbiB0aGUgaGlnaGVyIHRoZSBwb3ZlcnR5PyoqDQpgYGB7cn0NCmNvcnJlbGF0aW9uIChpbmQsIGRmX2ZpbGwsIHF1byhvdXRfc2NoX2NoaWxkKSwgcXVvKHBvdl9yYXRpbyksICJvdXRfc2NoX2NoaWxkIiwgInBvdl9yYXRpbyIpDQpgYGANCg0KDQoqKklzIGEgbW9yZSBlZHVjYXRlZCBzb2NpZXR5IG1vcmUgb3IgbGVzcyBlcXVhbD8qKg0KYGBge3J9DQoNCmNvcnJlbGF0aW9uIChpbmQsIGRmX2ZpbGwsIHF1byhpbmVxXzEwKSwgcXVvKG91dF9zY2hfY2hpbGQpLCAiaW5lcV8xMCIsICJvdXRfc2NoX2NoaWxkIikNCg0KYGBgDQoNCg0KKipJcyBhIG1vcmUgcG92ZXJ0eSBzb2NpZXR5IG1vcmUgb3IgbGVzcyBlcXVhbD8qKg0KYGBge3J9DQpjb3JyZWxhdGlvbiAoaW5kLCBkZl9maWxsLCBxdW8oaW5lcV8xMCksIHF1byhwb3ZfcmF0aW8pLCAiaW5lcV8xMCIsICJwb3ZfcmF0aW8iKQ0KYGBgDQoNCg0KIyBTcGVjaWZpYyBHcmFwaGljcw0KDQojIExpbWl0cyAtIHVwcGVyIGFuZCBsb3dlciAtIEluY29tZSBJbmVxdWFsaXR5IEFuYWx5c2lzIA0KDQoqKkhvdyBtdWNoIGRpZmZlcmVuY2UgaW4gaW5jb21lIGhhcyB0aGUgcmljaGVzdCAxMCUgb2YgdGhlIHBvcHVsYXRpb24gY29tcGFyZWQgdG8gdGhlIHBvb3Jlc3Q/IFdoZXJlIGFyZSB0aGVzZSBkaWZmZXJlbmNlcyBtb3N0IGRpc2NyZXBhbnQ/KioNCg0KYGBge3IgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTE1fSANCiAgICAgICAgIyBoZWlnaHQ9MTAvNzANCg0KIyBQbG90dGluZyB0aGUgSW5jb21lIGluZXF1YWxpdHkgZ3JhcGggDQoNCmluY29tZTEwICU+JQ0Kc2xpY2VfbWF4KGluZXFfMTAsIG4gPSA0MCklPiUNCmdncGxvdCAoYWVzICh4PSB2YWx1ZXMsICB5ID0gcmVvcmRlcihjb3VudHJ5X25hbWUsIGluZXFfMTAsIG1heCksIGNvbG9yID0gaW5kaWNhdG9yKSkrDQogIGdlb21fcG9pbnQoKSsNCiAgc2NhbGVfY29sb3JfbWFudWFsICh2YWx1ZXMgPSBjKCJkZWVwc2t5Ymx1ZTQiLCAiZmlyZWJyaWNrIiksIGxhYmVscyA9IGMoIkluY29tZSBieSBoaWdoZXN0IDEwJSIsICJJbmNvbWUgYnkgbG93ZXN0IDEwJSIpKSsNCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAiQ2FsaWJyaSIsIHNpemUgPSA1MCkpKw0KICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gY291bnRyeV9uYW1lKSwgY29sb3IgPSAiZ3JleTUwIikrDQogIGxhYnMgKHRpdGxlID0gIkluY29tZSBzaGFyZSBoZWxkIGJ5IGxvd2VzdCAxMCUgYW5kIGhpZ2hlciAxMCUiLCBzdWJ0aXRsZT0gIm9yZGVyaW5nIGJ5IHBlcmNlbnRhZ2Ugb2YgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBoaWdoZXIgMTAlIGFuZCB0aGUgbG93ZXIgMTAlIix4ID0gImluY29tZSBzaGFyZSBoZWxkIGJ5IGxvd2VzdCAxMCUgYW5kIGhpZ2hlciAxMCUiLCB5ID0gIkNvdW50cmllcyIsIGNhcHRpb24gPSAiTGF0ZXN0IGRhdGEgYmV0d2VlbiB0aGUgeWVhcnMgMjAxMCB0byAyMDIwIikrDQogIHRoZW1lX2NsYXNzaWMoKSsNCiAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImdyYXk5NSIpKSsNCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsNjApKSsNCiAgI3RoZW1lKCBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2xpbmUobGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAibGlnaHRncmF5IikpKw0KICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3I9J2dyYXk1MCcsIGZpbGwgPSBOQSkpKw0KICBnZW9tX3RleHQgKGFlcyhsYWJlbCA9IHZhbHVlcyksICwgdmp1c3QgPSAtMSkrICNudWRnZV95PS4zDQogIGdlb21fbGFiZWwgKGFlcyAoeD02MCxsYWJlbCA9IHNwcmludGYoIiUuMWYlJSIsIGluZXFfMTApKSwgY29sb3IgPSAiYmxhY2siKSsNCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApKQ0KICAjZmFjZXRfd3JhcCAoJ2NvbnRpbmVudCcsIHNjYWxlcyA9ICdmcmVlX3knKQ0KDQpgYGANCg0KU291dGggQWZyaWNhIGlzIHRoZSBjb3VudHJ5IHdpdGggdGhlIGdyZWF0ZXN0IHBlcmNlbnRhZ2UgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBpbmNvbWUgc2hhcmUgaGVsZCBieSBoaWdoZXIgMTAlIGFuZCBsb3dlc3QgMTAlLCBmb2xsb3dlZCBieSBOYW1pYmlhIGFuZCBaYW1iaWEuDQoNClRoZSAxMCUgb2YgdGhlIHBvcHVsYXRpb24gd2l0aCB0aGUgaGlnaGVzdCBkaXNwb3NhYmxlIGluY29tZSBpbiBTb3V0aCBBZnJpY2EgcmVjZWl2ZWQgNTUgdGltZXMgYXMgbXVjaCBpbmNvbWUgYXMgdGhlIDEwJSB3aXRoIHRoZSBsb3dlc3QgZGlzcG9zYWJsZSBpbmNvbWUuDQoNCiMgTGltaXRzIC0gdXBwZXIgYW5kIGxvd2VyIGJ5IGNvbnRpbmV0IC0gSW5jb21lIEluZXF1YWxpdHkgQW5hbHlzaXMgYnkgY29udGluZW50DQoNCmBgYHtyIGZpZy5oZWlnaHQ9NTAsIGZpZy53aWR0aD0xNX0NCg0KIyBQbG90dGluZyB0aGUgSW5jb21lIGluZXF1YWxpdHkgZ3JhcGggZmFjZXRfd3JhcCBieSBjb250aW5lbnQNCg0KaW5jb21lMTAlPiUNCiAgDQpnZ3Bsb3QgKGFlcyAoeD0gdmFsdWVzLCAgeSA9IHJlb3JkZXIoY291bnRyeV9uYW1lLCBpbmVxXzEwLCBtYXgpLCBjb2xvciA9IGluZGljYXRvcikpKw0KICBnZW9tX3BvaW50KCkrDQogIHNjYWxlX2NvbG9yX21hbnVhbCAodmFsdWVzID0gYygiZGVlcHNreWJsdWU0IiwgImZpcmVicmljayIpLCBsYWJlbHMgPSBjKCJJbmNvbWUgYnkgaGlnaGVzdCAxMCUiLCAiSW5jb21lIGJ5IGxvd2VzdCAxMCUiKSkrDQogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIkNhbGlicmkiLCBzaXplID0gNTApKSsNCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IGNvdW50cnlfbmFtZSksIGNvbG9yID0gImdyZXk1MCIpKw0KICAgbGFicyAodGl0bGUgPSAiSW5jb21lIHNoYXJlIGhlbGQgYnkgbG93ZXN0IDEwJSBhbmQgaGlnaGVyIDEwJSIsIHN1YnRpdGxlPSAib3JkZXJpbmcgYnkgcGVyY2VudGFnZSBvZiBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIGhpZ2hlciAxMCUgYW5kIHRoZSBsb3dlciAxMCUiLHggPSAiaW5jb21lIHNoYXJlIGhlbGQgYnkgbG93ZXN0IDEwJSBhbmQgaGlnaGVyIDEwJSIsIHkgPSAiQ291bnRyaWVzIiwgY2FwdGlvbiA9ICJMYXRlc3QgZGF0YSBiZXR3ZWVuIHRoZSB5ZWFycyAyMDEwIHRvIDIwMjAiKSsNCiAgdGhlbWVfY2xhc3NpYygpKw0KICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiZ3JheTk1IikpKw0KICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMCw2NSkpKw0KICAjdGhlbWUoIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfbGluZShsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJsaWdodGdyYXkiKSkrDQogIHRoZW1lKHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvcj0nZ3JheTUwJywgZmlsbCA9IE5BKSkrDQogIGdlb21fdGV4dCAoYWVzIChsYWJlbCA9IHZhbHVlcyksIHZqdXN0ID0gLTEpKw0KICBnZW9tX2xhYmVsIChhZXMgKHg9NjAsbGFiZWwgPSBzcHJpbnRmKCIlLjFmJSUiLCBpbmVxXzEwKSksIGNvbG9yID0gImJsYWNrIikrDQogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSkrDQogIGZhY2V0X3dyYXAgKCdjb250aW5lbnQnLCBzY2FsZXMgPSAnZnJlZV95JykNCiAgDQpgYGANCg0KIyBHcmlmc2t5IC0gRGVuc2l0eSAtIFF1aW50aWxlcyAtIEluY2x1ZGluZyB0aGUgaW5jb21lIHNoYXJlIGhlbGQgYnkgcXVpbnRpbGVzIG9mIHBvcHVsYXRpb24NCg0KKipIb3cgbXVjaCBkaWZmZXJlbmNlIGluIGluY29tZSBoYXMgdGhlIHJpY2hlc3QgMjAlIG9mIHRoZSBwb3B1bGF0aW9uIGNvbXBhcmVkIHRvIHRoZSBwb29yZXN0IDIwJSBhbmQgdG8gdGhlIG90aGVyIHF1aW50aWxlcz8qKg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTgwLCBmaWcud2lkdGg9MjB9DQoNCg0KaW5jb21lMjAlPiUNCiNzbGljZV9tYXgoaW5lcV8yMCwgbiA9IDgwKSU+JQ0KZ2dwbG90KGFlcyh4PXZhbHVlcywgeT0gcmVvcmRlcihjb3VudHJ5X25hbWUsIGluZXFfMjAsIG1heCksIGZpbGwgPSBmYWN0b3Ioc3RhdChkZXNjKHF1YW50aWxlKSkpKSkgKw0KICBzdGF0X2RlbnNpdHlfcmlkZ2VzKA0KICAgIGdlb20gPSAiZGVuc2l0eV9yaWRnZXNfZ3JhZGllbnQiLCBjYWxjX2VjZGYgPSBUUlVFLA0KICAgIHF1YW50aWxlcyA9IDUsIHF1YW50aWxlX2xpbmVzID0gVFJVRQ0KICApICsNCiAgIGxhYnMgKHRpdGxlID0gIkluY29tZSBzaGFyZSBoZWxkIGJ5IHBvcHVsYXRpb24iLCBzdWJ0aXRsZT0gIm9yZGVyaW5nIGJ5IHBlcmNlbnRhZ2Ugb2YgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBoaWdoZXIgMjAlIGFuZCB0aGUgbG93ZXIgMjAlIiwgeCA9ICJpbmNvbWUgc2hhcmUgaGVsZCAlIiwgY2FwdGlvbiA9ICJMYXRlc3QgZGF0YSBiZXR3ZWVuIHRoZSB5ZWFycyAyMDEwIHRvIDIwMjAiKSsNCiAgIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDI1KSkrDQogICBzY2FsZV9maWxsX3ZpcmlkaXNfZChuYW1lID0gIlF1aW50aWxlcyIsIG9wdGlvbiA9ICJDIikNCg0KYGBgDQpUaGUgZ3JhcGhpYyBhYm92ZSBzaG93IHRoZToNCkluY29tZSBzaGFyZSBoZWxkIGJ5IGxvd2VzdCAyMCUgKHRoZSBwb29yZXN0IDIwJSkNCkluY29tZSBzaGFyZSBoZWxkIGJ5IDJuZCBxdWludGlsZSAyMCUgLSA0MCUNCkluY29tZSBzaGFyZSBoZWxkIGJ5IDNyZCAgcXVpbnRpbGUgIDQwJSAtIDYwJQ0KSW5jb21lIHNoYXJlIGhlbGQgYnkgNHRoIHF1aW50aWxlICA2MCUgLSA4MCUNCkluY29tZSBzaGFyZSBoZWxkIGJ5IDV0aCBxdWludGlsZSAgODAlIC0gMTAwJSAodGhlIHJpY2hlc3QgMjAlKQ0KDQpJdCBzZXJ2ZXMgdG8gZ2l2ZSB1cyBhbiBpZGVhIG9mIHRoZSBpbmVxdWFsaXR5IGFtb25nIHRoZSBwb3B1bGF0aW9uLg0KDQoNCiMgQW5pbWF0ZWQgQ29ycmVsYXRpb24NCg0KIyBUaGlzIGNvZGUgZ2VuZXJhdGVzIGEgYW5uaW1hdGVkIGdyYXBoIHdpdGggdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gMiB2YXJpYWJsZXMgYWxvbmcgdGhlIHllYXJzIA0KYGBge3IgZmlnLndpZHRoPTEyfQ0KZGZfZmllbGRzPC0gaW5kDQpkZjE8LSBkZl9maWxsX2hpc3QNCmluZGljYXRvcjEgPC1xdW8ob3V0X3NjaF9jaGlsZCkNCmluZGljYXRvcjIgPC0gcXVvKHBvdl9yYXRpbykNCmluZDEgPC0gIm91dF9zY2hfY2hpbGQiDQppbmQyIDwtICJwb3ZfcmF0aW8iDQoNCiMgVGV4dCBmb3IgdGl0bGUNCnNlcmllczEgPC0gc3Vic2V0IChkZl9maWVsZHMsIGluZGljYXRvcj09aW5kMSwgc2VsZWN0PSAic2VyaWVzIikNCnVuaXQxIDwtIHN1YnNldCAoZGZfZmllbGRzLCBpbmRpY2F0b3I9PWluZDEsIHNlbGVjdD0gInVuaXQiKQ0Kc2VyaWVzMiA8LSBzdWJzZXQgKGRmX2ZpZWxkcywgaW5kaWNhdG9yPT1pbmQyLCBzZWxlY3Q9ICJzZXJpZXMiKQ0KdW5pdDIgPC0gc3Vic2V0IChkZl9maWVsZHMsIGluZGljYXRvcj09aW5kMiwgc2VsZWN0PSAidW5pdCIpDQoNCmxhYl94IDwtIHBhc3RlIChzZXJpZXMxLCB1bml0MSkNCmxhYl95IDwtIHBhc3RlIChzZXJpZXMyLCB1bml0MikNCmxhYl90aXRsZSA8LSBwYXN0ZSAobGFiX3gsICJ4IiwgbGFiX3ksICJhbG9uZyB0aGUgeWVhcnMiKQ0KICANCmRmMSU+JQ0KICBkcm9wX25hICghIWluZGljYXRvcjEsICEhaW5kaWNhdG9yMikNCiAjIGZpbHRlciAoY29udGluZW50ID09ICJBc2lhIikNCg0KcDwtIGdncGxvdCAoZGYxLCBhZXMgKHg9ICEhaW5kaWNhdG9yMSwgeT0gISFpbmRpY2F0b3IyLCBjb2xvciA9IGNvdW50cnlfbmFtZSwgc2l6ZSA9IHBvcCkpKw0KICBnZW9tX3BvaW50KGFscGhhID0gMC43LCBzaG93LmxlZ2VuZCA9IEZBTFNFKSsNCiAgc2NhbGVfY29sb3VyX2Rpc2NyZXRlKCkrDQogIHNjYWxlX3NpemUocmFuZ2UgPSBjKDIsIDEyKSkgKw0KICBsYWJzICh0aXRsZSA9ICJZZWFyOiB7ZnJhbWVfdGltZX0iLCB4PWxhYl94LCB5ID0gbGFiX3ksIGNhcHRpb24gPSAiTGF0ZXN0IGRhdGEgYmV0d2VlbiB0aGUgeWVhcnMgMjAxMCB0byAyMDIwIikrDQogIGZhY2V0X3dyYXAgKCdjb250aW5lbnQnLCBzY2FsZXMgPSAnZnJlZScpKw0KICB0cmFuc2l0aW9uX3RpbWUgKHllYXIpKyAjIGFuaW1hdGlvbg0KICBlYXNlX2FlcygnbGluZWFyJykNCg0KYW5pbWF0ZShwLCByZW5kZXJlciA9IGdpZnNraV9yZW5kZXJlcigpKQ0KDQpgYGANCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQo=